经过前面几章的简单介绍,我们已经大致了解了jvm的启动框架和执行流程了。不过,这些都是些无关痛痒的问题,几行文字描述一下即可。
所以,今天我们从另一个角度来讲解jvm的一些东西,以便可以更多一点认知。即如题:jvm是如何找到对应的java方法,然后执行的呢?(但是执行太复杂,太重要,我们就不说了。我们单看如何找到对应的java方法吧)
1. 回顾核心变量JNIEnv的初始化
如上一篇系列文章中讲到的,jdk执行的核心方法,实际上也是调用jvm或者hotspot的接口方法实现的,这其中有个重要变量,供jdk使用。即:JNIEnv* env 。可见其重要性。我们再来回顾下它的初始化过程。
//实际上,我们可以通过前面对 JNIEnv **penv 的赋值中查到端倪: // hotspot/src/share/vm/prims/jni.cpp ... // 将jvm信息存储到 penv 中,以备外部使用 *(JNIEnv**)penv = thread->jni_environment(); ... // 而查看 jni_environment() 方法可知,其由一个类变量 _jni_environment 处理 // share/vm/runtime/thread.hpp // Returns the jni environment for this thread JNIEnv* jni_environment() { return &_jni_environment; } // 所以,我们只需找出 _jni_environment 是如何赋值初始化,即可知道如何获取这个关键变量的逻辑了。结果是,在创建JavaThread, 在进行初始化时,便会设置该值。 // share/vm/runtime/thread.cpp JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) : Thread() #if INCLUDE_ALL_GCS , _satb_mark_queue(&_satb_mark_queue_set), _dirty_card_queue(&_dirty_card_queue_set) #endif // INCLUDE_ALL_GCS { if (TraceThreadEvents) { tty->print_cr("creating thread %p", this); } // 初始化线程变量信息, 如 JNIEnv initialize(); _jni_attach_state = _not_attaching_via_jni; set_entry_point(entry_point); // Create the native thread itself. // %note runtime_23 os::ThreadType thr_type = os::java_thread; thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread : os::java_thread; os::create_thread(this, thr_type, stack_sz); _safepoint_visible = false; // The _osthread may be NULL here because we ran out of memory (too many threads active). // We need to throw and OutOfMemoryError - however we cannot do this here because the caller // may hold a lock and all locks must be unlocked before throwing the exception (throwing // the exception consists of creating the exception object & initializing it, initialization // will leave the VM via a JavaCall and then all locks must be unlocked). // // The thread is still suspended when we reach here. Thread must be explicit started // by creator! Furthermore, the thread must also explicitly be added to the Threads list // by calling Threads:add. The reason why this is not done here, is because the thread // object must be fully initialized (take a look at JVM_Start) } // A JavaThread is a normal Java thread void JavaThread::initialize() { // Initialize fields // Set the claimed par_id to -1 (ie not claiming any par_ids) set_claimed_par_id(-1); set_saved_exception_pc(NULL); set_threadObj(NULL); _anchor.clear(); set_entry_point(NULL); // 取数jni_functions, 初始化到 _jni_environment set_jni_functions(jni_functions()); set_callee_target(NULL); set_vm_result(NULL); set_vm_result_2(NULL); set_vframe_array_head(NULL); set_vframe_array_last(NULL); set_deferred_locals(NULL); set_deopt_mark(NULL); set_deopt_nmethod(NULL); clear_must_deopt_id(); set_monitor_chunks(NULL); set_next(NULL); set_thread_state(_thread_new); #if INCLUDE_NMT set_recorder(NULL); #endif _terminated = _not_terminated; _privileged_stack_top = NULL; _array_for_gc = NULL; _suspend_equivalent = false; _in_deopt_handler = 0; _doing_unsafe_access = false; _stack_guard_state = stack_guard_unused; (void)const_cast<oop&>(_exception_oop = NULL); _exception_pc = 0; _exception_handler_pc = 0; _is_method_handle_return = 0; _jvmti_thread_state= NULL; _should_post_on_exceptions_flag = JNI_FALSE; _jvmti_get_loaded_classes_closure = NULL; _interp_only_mode = 0; _special_runtime_exit_condition = _no_async_condition; _pending_async_exception = NULL; _thread_stat = NULL; _thread_stat = new ThreadStatistics(); _blocked_on_compilation = false; _jni_active_critical = 0; _do_not_unlock_if_synchronized = false; _cached_monitor_info = NULL; _parker = Parker::Allocate(this) ; #ifndef PRODUCT _jmp_ring_index = 0; for (int ji = 0 ; ji < jump_ring_buffer_size ; ji++ ) { record_jump(NULL, NULL, NULL, 0); } #endif /* PRODUCT */ set_thread_profiler(NULL); if (FlatProfiler::is_active()) { // This is where we would decide to either give each thread it's own profiler // or use one global one from FlatProfiler, // or up to some count of the number of profiled threads, etc. ThreadProfiler* pp = new ThreadProfiler(); pp->engage(); set_thread_profiler(pp); } // Setup safepoint state info for this thread ThreadSafepointState::create(this); debug_only(_java_call_counter = 0); // JVMTI PopFrame support _popframe_condition = popframe_inactive; _popframe_preserved_args = NULL; _popframe_preserved_args_size = 0; pd_initialize(); } // Returns the function structure struct JNINativeInterface_* jni_functions() { #if INCLUDE_JNI_CHECK if (CheckJNICalls) return jni_functions_check(); #endif // INCLUDE_JNI_CHECK return &jni_NativeInterface; } // thread.hpp //JNI functiontable getter/setter for JVMTI jni function table interception API. void set_jni_functions(struct JNINativeInterface_* functionTable) { _jni_environment.functions = functionTable; }