经过前面几章的简单介绍,我们已经大致了解了jvm的启动框架和执行流程了。不过,这些都是些无关痛痒的问题,几行文字描述一下即可。

  所以,今天我们从另一个角度来讲解jvm的一些东西,以便可以更多一点认知。即如题:jvm是如何找到对应的java方法,然后执行的呢?(但是执行太复杂,太重要,我们就不说了。我们单看如何找到对应的java方法吧)

 

  如上一篇系列文章中讲到的,jdk执行的核心方法,实际上也是调用jvm或者hotspot的接口方法实现的,这其中有个重要变量,供jdk使用。即:JNIEnv* env 。可见其重要性。我们再来回顾下它的初始化过程。

  1. //实际上,我们可以通过前面对 JNIEnv **penv 的赋值中查到端倪:
  2. // hotspot/src/share/vm/prims/jni.cpp
  3. ...
  4. // 将jvm信息存储到 penv 中,以备外部使用
  5. *(JNIEnv**)penv = thread->jni_environment();
  6. ...
  7. // 而查看 jni_environment() 方法可知,其由一个类变量 _jni_environment 处理
  8. // share/vm/runtime/thread.hpp
  9. // Returns the jni environment for this thread
  10. JNIEnv* jni_environment() { return &_jni_environment; }
  11. // 所以,我们只需找出 _jni_environment 是如何赋值初始化,即可知道如何获取这个关键变量的逻辑了。结果是,在创建JavaThread, 在进行初始化时,便会设置该值。
  12. // share/vm/runtime/thread.cpp
  13. JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) :
  14. Thread()
  15. #if INCLUDE_ALL_GCS
  16. , _satb_mark_queue(&_satb_mark_queue_set),
  17. _dirty_card_queue(&_dirty_card_queue_set)
  18. #endif // INCLUDE_ALL_GCS
  19. {
  20. if (TraceThreadEvents) {
  21. tty->print_cr("creating thread %p", this);
  22. }
  23. // 初始化线程变量信息, 如 JNIEnv
  24. initialize();
  25. _jni_attach_state = _not_attaching_via_jni;
  26. set_entry_point(entry_point);
  27. // Create the native thread itself.
  28. // %note runtime_23
  29. os::ThreadType thr_type = os::java_thread;
  30. thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread :
  31. os::java_thread;
  32. os::create_thread(this, thr_type, stack_sz);
  33. _safepoint_visible = false;
  34. // The _osthread may be NULL here because we ran out of memory (too many threads active).
  35. // We need to throw and OutOfMemoryError - however we cannot do this here because the caller
  36. // may hold a lock and all locks must be unlocked before throwing the exception (throwing
  37. // the exception consists of creating the exception object & initializing it, initialization
  38. // will leave the VM via a JavaCall and then all locks must be unlocked).
  39. //
  40. // The thread is still suspended when we reach here. Thread must be explicit started
  41. // by creator! Furthermore, the thread must also explicitly be added to the Threads list
  42. // by calling Threads:add. The reason why this is not done here, is because the thread
  43. // object must be fully initialized (take a look at JVM_Start)
  44. }
  45. // A JavaThread is a normal Java thread
  46. void JavaThread::initialize() {
  47. // Initialize fields
  48. // Set the claimed par_id to -1 (ie not claiming any par_ids)
  49. set_claimed_par_id(-1);
  50. set_saved_exception_pc(NULL);
  51. set_threadObj(NULL);
  52. _anchor.clear();
  53. set_entry_point(NULL);
  54. // 取数jni_functions, 初始化到 _jni_environment
  55. set_jni_functions(jni_functions());
  56. set_callee_target(NULL);
  57. set_vm_result(NULL);
  58. set_vm_result_2(NULL);
  59. set_vframe_array_head(NULL);
  60. set_vframe_array_last(NULL);
  61. set_deferred_locals(NULL);
  62. set_deopt_mark(NULL);
  63. set_deopt_nmethod(NULL);
  64. clear_must_deopt_id();
  65. set_monitor_chunks(NULL);
  66. set_next(NULL);
  67. set_thread_state(_thread_new);
  68. #if INCLUDE_NMT
  69. set_recorder(NULL);
  70. #endif
  71. _terminated = _not_terminated;
  72. _privileged_stack_top = NULL;
  73. _array_for_gc = NULL;
  74. _suspend_equivalent = false;
  75. _in_deopt_handler = 0;
  76. _doing_unsafe_access = false;
  77. _stack_guard_state = stack_guard_unused;
  78. (void)const_cast<oop&>(_exception_oop = NULL);
  79. _exception_pc = 0;
  80. _exception_handler_pc = 0;
  81. _is_method_handle_return = 0;
  82. _jvmti_thread_state= NULL;
  83. _should_post_on_exceptions_flag = JNI_FALSE;
  84. _jvmti_get_loaded_classes_closure = NULL;
  85. _interp_only_mode = 0;
  86. _special_runtime_exit_condition = _no_async_condition;
  87. _pending_async_exception = NULL;
  88. _thread_stat = NULL;
  89. _thread_stat = new ThreadStatistics();
  90. _blocked_on_compilation = false;
  91. _jni_active_critical = 0;
  92. _do_not_unlock_if_synchronized = false;
  93. _cached_monitor_info = NULL;
  94. _parker = Parker::Allocate(this) ;
  95. #ifndef PRODUCT
  96. _jmp_ring_index = 0;
  97. for (int ji = 0 ; ji < jump_ring_buffer_size ; ji++ ) {
  98. record_jump(NULL, NULL, NULL, 0);
  99. }
  100. #endif /* PRODUCT */
  101. set_thread_profiler(NULL);
  102. if (FlatProfiler::is_active()) {
  103. // This is where we would decide to either give each thread it\'s own profiler
  104. // or use one global one from FlatProfiler,
  105. // or up to some count of the number of profiled threads, etc.
  106. ThreadProfiler* pp = new ThreadProfiler();
  107. pp->engage();
  108. set_thread_profiler(pp);
  109. }
  110. // Setup safepoint state info for this thread
  111. ThreadSafepointState::create(this);
  112. debug_only(_java_call_counter = 0);
  113. // JVMTI PopFrame support
  114. _popframe_condition = popframe_inactive;
  115. _popframe_preserved_args = NULL;
  116. _popframe_preserved_args_size = 0;
  117. pd_initialize();
  118. }
  119. // Returns the function structure
  120. struct JNINativeInterface_* jni_functions() {
  121. #if INCLUDE_JNI_CHECK
  122. if (CheckJNICalls) return jni_functions_check();
  123. #endif // INCLUDE_JNI_CHECK
  124. return &jni_NativeInterface;
  125. }
  126. // thread.hpp
  127. //JNI functiontable getter/setter for JVMTI jni function table interception API.
  128. void set_jni_functions(struct JNINativeInterface_* functionTable) {
  129. _jni_environment.functions = functionTable;
  130. }

  所以,核心的初始化变成了 jni_NativeInterface 的具体值问题了。刚好我们可以通过这个方法去这个 JNIEnv 都定义了啥。这对于我们以后的分析工作有非常大的帮助。

  1. // jni.cpp
  2. // Structure containing all jni functions
  3. struct JNINativeInterface_ jni_NativeInterface = {
  4. NULL,
  5. NULL,
  6. NULL,
  7. NULL,
  8. jni_GetVersion,
  9. jni_DefineClass,
  10. jni_FindClass,
  11. jni_FromReflectedMethod,
  12. jni_FromReflectedField,
  13. jni_ToReflectedMethod,
  14. jni_GetSuperclass,
  15. jni_IsAssignableFrom,
  16. jni_ToReflectedField,
  17. jni_Throw,
  18. jni_ThrowNew,
  19. jni_ExceptionOccurred,
  20. jni_ExceptionDescribe,
  21. jni_ExceptionClear,
  22. jni_FatalError,
  23. jni_PushLocalFrame,
  24. jni_PopLocalFrame,
  25. jni_NewGlobalRef,
  26. jni_DeleteGlobalRef,
  27. jni_DeleteLocalRef,
  28. jni_IsSameObject,
  29. jni_NewLocalRef,
  30. jni_EnsureLocalCapacity,
  31. jni_AllocObject,
  32. jni_NewObject,
  33. jni_NewObjectV,
  34. jni_NewObjectA,
  35. jni_GetObjectClass,
  36. jni_IsInstanceOf,
  37. jni_GetMethodID,
  38. jni_CallObjectMethod,
  39. jni_CallObjectMethodV,
  40. jni_CallObjectMethodA,
  41. jni_CallBooleanMethod,
  42. jni_CallBooleanMethodV,
  43. jni_CallBooleanMethodA,
  44. jni_CallByteMethod,
  45. jni_CallByteMethodV,
  46. jni_CallByteMethodA,
  47. jni_CallCharMethod,
  48. jni_CallCharMethodV,
  49. jni_CallCharMethodA,
  50. jni_CallShortMethod,
  51. jni_CallShortMethodV,
  52. jni_CallShortMethodA,
  53. jni_CallIntMethod,
  54. jni_CallIntMethodV,
  55. jni_CallIntMethodA,
  56. jni_CallLongMethod,
  57. jni_CallLongMethodV,
  58. jni_CallLongMethodA,
  59. jni_CallFloatMethod,
  60. jni_CallFloatMethodV,
  61. jni_CallFloatMethodA,
  62. jni_CallDoubleMethod,
  63. jni_CallDoubleMethodV,
  64. jni_CallDoubleMethodA,
  65. jni_CallVoidMethod,
  66. jni_CallVoidMethodV,
  67. jni_CallVoidMethodA,
  68. jni_CallNonvirtualObjectMethod,
  69. jni_CallNonvirtualObjectMethodV,
  70. jni_CallNonvirtualObjectMethodA,
  71. jni_CallNonvirtualBooleanMethod,
  72. jni_CallNonvirtualBooleanMethodV,
  73. jni_CallNonvirtualBooleanMethodA,
  74. jni_CallNonvirtualByteMethod,
  75. jni_CallNonvirtualByteMethodV,
  76. jni_CallNonvirtualByteMethodA,
  77. jni_CallNonvirtualCharMethod,
  78. jni_CallNonvirtualCharMethodV,
  79. jni_CallNonvirtualCharMethodA,
  80. jni_CallNonvirtualShortMethod,
  81. jni_CallNonvirtualShortMethodV,
  82. jni_CallNonvirtualShortMethodA,
  83. jni_CallNonvirtualIntMethod,
  84. jni_CallNonvirtualIntMethodV,
  85. jni_CallNonvirtualIntMethodA,
  86. jni_CallNonvirtualLongMethod,
  87. jni_CallNonvirtualLongMethodV,
  88. jni_CallNonvirtualLongMethodA,
  89. jni_CallNonvirtualFloatMethod,
  90. jni_CallNonvirtualFloatMethodV,
  91. jni_CallNonvirtualFloatMethodA,
  92. jni_CallNonvirtualDoubleMethod,
  93. jni_CallNonvirtualDoubleMethodV,
  94. jni_CallNonvirtualDoubleMethodA,
  95. jni_CallNonvirtualVoidMethod,
  96. jni_CallNonvirtualVoidMethodV,
  97. jni_CallNonvirtualVoidMethodA,
  98. jni_GetFieldID,
  99. jni_GetObjectField,
  100. jni_GetBooleanField,
  101. jni_GetByteField,
  102. jni_GetCharField,
  103. jni_GetShortField,
  104. jni_GetIntField,
  105. jni_GetLongField,
  106. jni_GetFloatField,
  107. jni_GetDoubleField,
  108. jni_SetObjectField,
  109. jni_SetBooleanField,
  110. jni_SetByteField,
  111. jni_SetCharField,
  112. jni_SetShortField,
  113. jni_SetIntField,
  114. jni_SetLongField,
  115. jni_SetFloatField,
  116. jni_SetDoubleField,
  117. jni_GetStaticMethodID,
  118. jni_CallStaticObjectMethod,
  119. jni_CallStaticObjectMethodV,
  120. jni_CallStaticObjectMethodA,
  121. jni_CallStaticBooleanMethod,
  122. jni_CallStaticBooleanMethodV,
  123. jni_CallStaticBooleanMethodA,
  124. jni_CallStaticByteMethod,
  125. jni_CallStaticByteMethodV,
  126. jni_CallStaticByteMethodA,
  127. jni_CallStaticCharMethod,
  128. jni_CallStaticCharMethodV,
  129. jni_CallStaticCharMethodA,
  130. jni_CallStaticShortMethod,
  131. jni_CallStaticShortMethodV,
  132. jni_CallStaticShortMethodA,
  133. jni_CallStaticIntMethod,
  134. jni_CallStaticIntMethodV,
  135. jni_CallStaticIntMethodA,
  136. jni_CallStaticLongMethod,
  137. jni_CallStaticLongMethodV,
  138. jni_CallStaticLongMethodA,
  139. jni_CallStaticFloatMethod,
  140. jni_CallStaticFloatMethodV,
  141. jni_CallStaticFloatMethodA,
  142. jni_CallStaticDoubleMethod,
  143. jni_CallStaticDoubleMethodV,
  144. jni_CallStaticDoubleMethodA,
  145. jni_CallStaticVoidMethod,
  146. jni_CallStaticVoidMethodV,
  147. jni_CallStaticVoidMethodA,
  148. jni_GetStaticFieldID,
  149. jni_GetStaticObjectField,
  150. jni_GetStaticBooleanField,
  151. jni_GetStaticByteField,
  152. jni_GetStaticCharField,
  153. jni_GetStaticShortField,
  154. jni_GetStaticIntField,
  155. jni_GetStaticLongField,
  156. jni_GetStaticFloatField,
  157. jni_GetStaticDoubleField,
  158. jni_SetStaticObjectField,
  159. jni_SetStaticBooleanField,
  160. jni_SetStaticByteField,
  161. jni_SetStaticCharField,
  162. jni_SetStaticShortField,
  163. jni_SetStaticIntField,
  164. jni_SetStaticLongField,
  165. jni_SetStaticFloatField,
  166. jni_SetStaticDoubleField,
  167. jni_NewString,
  168. jni_GetStringLength,
  169. jni_GetStringChars,
  170. jni_ReleaseStringChars,
  171. jni_NewStringUTF,
  172. jni_GetStringUTFLength,
  173. jni_GetStringUTFChars,
  174. jni_ReleaseStringUTFChars,
  175. jni_GetArrayLength,
  176. jni_NewObjectArray,
  177. jni_GetObjectArrayElement,
  178. jni_SetObjectArrayElement,
  179. jni_NewBooleanArray,
  180. jni_NewByteArray,
  181. jni_NewCharArray,
  182. jni_NewShortArray,
  183. jni_NewIntArray,
  184. jni_NewLongArray,
  185. jni_NewFloatArray,
  186. jni_NewDoubleArray,
  187. jni_GetBooleanArrayElements,
  188. jni_GetByteArrayElements,
  189. jni_GetCharArrayElements,
  190. jni_GetShortArrayElements,
  191. jni_GetIntArrayElements,
  192. jni_GetLongArrayElements,
  193. jni_GetFloatArrayElements,
  194. jni_GetDoubleArrayElements,
  195. jni_ReleaseBooleanArrayElements,
  196. jni_ReleaseByteArrayElements,
  197. jni_ReleaseCharArrayElements,
  198. jni_ReleaseShortArrayElements,
  199. jni_ReleaseIntArrayElements,
  200. jni_ReleaseLongArrayElements,
  201. jni_ReleaseFloatArrayElements,
  202. jni_ReleaseDoubleArrayElements,
  203. jni_GetBooleanArrayRegion,
  204. jni_GetByteArrayRegion,
  205. jni_GetCharArrayRegion,
  206. jni_GetShortArrayRegion,
  207. jni_GetIntArrayRegion,
  208. jni_GetLongArrayRegion,
  209. jni_GetFloatArrayRegion,
  210. jni_GetDoubleArrayRegion,
  211. jni_SetBooleanArrayRegion,
  212. jni_SetByteArrayRegion,
  213. jni_SetCharArrayRegion,
  214. jni_SetShortArrayRegion,
  215. jni_SetIntArrayRegion,
  216. jni_SetLongArrayRegion,
  217. jni_SetFloatArrayRegion,
  218. jni_SetDoubleArrayRegion,
  219. jni_RegisterNatives,
  220. jni_UnregisterNatives,
  221. jni_MonitorEnter,
  222. jni_MonitorExit,
  223. jni_GetJavaVM,
  224. jni_GetStringRegion,
  225. jni_GetStringUTFRegion,
  226. jni_GetPrimitiveArrayCritical,
  227. jni_ReleasePrimitiveArrayCritical,
  228. jni_GetStringCritical,
  229. jni_ReleaseStringCritical,
  230. jni_NewWeakGlobalRef,
  231. jni_DeleteWeakGlobalRef,
  232. jni_ExceptionCheck,
  233. jni_NewDirectByteBuffer,
  234. jni_GetDirectBufferAddress,
  235. jni_GetDirectBufferCapacity,
  236. // New 1_6 features
  237. jni_GetObjectRefType
  238. };

View Code

  以上就是 JNIEnv* env 变量的设值过程了,它借助于java线程的创建时机进行初始化。而后续的使用中,几乎都会仰仗它来运行,可见其重要性。

  但总结一下,这里面提供的接口,实际上都是一些非常基础的操作,比如变量新建,初始化,异常处理,锁处理,native注册等。类型实际并不多。这也提示了我们一点,越是基础的东西,实际上越不会那么复杂。它更多的是做好抽象工作,打好基础,比什么都好。

 

  要谈其他方法,着实也太泛了。因为,你可以定义这个方法,他可以定义一个别的方法。这里面的特性就太难找了。但,对于每个java应用的启动,都会去加载main()方法执行,所以,以这个main()方法的查找为出发点,定然能找到些端倪来。

  我们先来看看main()的调用地方如何:

  1. // share/bin/java.c
  2. // 加载 main 函数类
  3. // 通过引入 JavaMain(), 接入java方法
  4. // #define JNICALL __stdcall
  5. int JNICALL
  6. JavaMain(void * _args)
  7. {
  8. JavaMainArgs *args = (JavaMainArgs *)_args;
  9. int argc = args->argc;
  10. char **argv = args->argv;
  11. int mode = args->mode;
  12. char *what = args->what;
  13. // 一些jvm的调用实例,在之前的步骤中,通过加载相应动态链接方法,保存起来的
  14. /**
  15. * ifn->CreateJavaVM =
  16. * (void *)GetProcAddress(handle, "JNI_CreateJavaVM");
  17. * ifn->GetDefaultJavaVMInitArgs =
  18. * (void *)GetProcAddress(handle, "JNI_GetDefaultJavaVMInitArgs");
  19. */
  20. InvocationFunctions ifn = args->ifn;
  21. JavaVM *vm = 0;
  22. JNIEnv *env = 0;
  23. jclass mainClass = NULL;
  24. jclass appClass = NULL; // actual application class being launched
  25. jmethodID mainID;
  26. jobjectArray mainArgs;
  27. int ret = 0;
  28. jlong start, end;
  29. // collector
  30. RegisterThread();
  31. /* Initialize the virtual machine */
  32. start = CounterGet();
  33. // 重点1:初始化jvm,失败则退出
  34. // 此处会将重要变量 *env 进程初始化,从而使后续可用
  35. if (!InitializeJVM(&vm, &env, &ifn)) {
  36. JLI_ReportErrorMessage(JVM_ERROR1);
  37. exit(1);
  38. }
  39. // jvm检查完毕,如果只是一些展示类请求,则展示信息后,退出jvm
  40. if (showSettings != NULL) {
  41. ShowSettings(env, showSettings);
  42. /**
  43. * 宏是神奇的操作,此处 *env 直接引用
  44. #define CHECK_EXCEPTION_LEAVE(CEL_return_value) \
  45. do { \
  46. if ((*env)->ExceptionOccurred(env)) { \
  47. JLI_ReportExceptionDescription(env); \
  48. ret = (CEL_return_value); \
  49. LEAVE(); \
  50. } \
  51. } while (JNI_FALSE)
  52. */
  53. CHECK_EXCEPTION_LEAVE(1);
  54. }
  55. // 调用 LEAVE() 方法的目的在于主动销毁jvm线程
  56. // 且退出当前方法调用,即 LEAVE() 后方法不再被执行
  57. /*
  58. * Always detach the main thread so that it appears to have ended when
  59. * the application\'s main method exits. This will invoke the
  60. * uncaught exception handler machinery if main threw an
  61. * exception. An uncaught exception handler cannot change the
  62. * launcher\'s return code except by calling System.exit.
  63. *
  64. * Wait for all non-daemon threads to end, then destroy the VM.
  65. * This will actually create a trivial new Java waiter thread
  66. * named "DestroyJavaVM", but this will be seen as a different
  67. * thread from the one that executed main, even though they are
  68. * the same C thread. This allows mainThread.join() and
  69. * mainThread.isAlive() to work as expected.
  70. */
  71. /**
  72. *
  73. *
  74. #define LEAVE() \
  75. do { \
  76. if ((*vm)->DetachCurrentThread(vm) != JNI_OK) { \
  77. JLI_ReportErrorMessage(JVM_ERROR2); \
  78. ret = 1; \
  79. } \
  80. if (JNI_TRUE) { \
  81. (*vm)->DestroyJavaVM(vm); \
  82. return ret; \
  83. } \
  84. } while (JNI_FALSE)
  85. */
  86. if (printVersion || showVersion) {
  87. PrintJavaVersion(env, showVersion);
  88. CHECK_EXCEPTION_LEAVE(0);
  89. if (printVersion) {
  90. LEAVE();
  91. }
  92. }
  93. /* If the user specified neither a class name nor a JAR file */
  94. if (printXUsage || printUsage || what == 0 || mode == LM_UNKNOWN) {
  95. PrintUsage(env, printXUsage);
  96. CHECK_EXCEPTION_LEAVE(1);
  97. LEAVE();
  98. }
  99. // 释放内存
  100. FreeKnownVMs(); /* after last possible PrintUsage() */
  101. if (JLI_IsTraceLauncher()) {
  102. end = CounterGet();
  103. JLI_TraceLauncher("%ld micro seconds to InitializeJVM\n",
  104. (long)(jint)Counter2Micros(end-start));
  105. }
  106. /* At this stage, argc/argv have the application\'s arguments */
  107. if (JLI_IsTraceLauncher()){
  108. int i;
  109. printf("%s is \'%s\'\n", launchModeNames[mode], what);
  110. printf("App\'s argc is %d\n", argc);
  111. for (i=0; i < argc; i++) {
  112. printf(" argv[%2d] = \'%s\'\n", i, argv[i]);
  113. }
  114. }
  115. ret = 1;
  116. /*
  117. * Get the application\'s main class.
  118. *
  119. * See bugid 5030265. The Main-Class name has already been parsed
  120. * from the manifest, but not parsed properly for UTF-8 support.
  121. * Hence the code here ignores the value previously extracted and
  122. * uses the pre-existing code to reextract the value. This is
  123. * possibly an end of release cycle expedient. However, it has
  124. * also been discovered that passing some character sets through
  125. * the environment has "strange" behavior on some variants of
  126. * Windows. Hence, maybe the manifest parsing code local to the
  127. * launcher should never be enhanced.
  128. *
  129. * Hence, future work should either:
  130. * 1) Correct the local parsing code and verify that the
  131. * Main-Class attribute gets properly passed through
  132. * all environments,
  133. * 2) Remove the vestages of maintaining main_class through
  134. * the environment (and remove these comments).
  135. *
  136. * This method also correctly handles launching existing JavaFX
  137. * applications that may or may not have a Main-Class manifest entry.
  138. */
  139. // 重点2:加载 main 指定的class类
  140. mainClass = LoadMainClass(env, mode, what);
  141. CHECK_EXCEPTION_NULL_LEAVE(mainClass);
  142. /*
  143. * In some cases when launching an application that needs a helper, e.g., a
  144. * JavaFX application with no main method, the mainClass will not be the
  145. * applications own main class but rather a helper class. To keep things
  146. * consistent in the UI we need to track and report the application main class.
  147. */
  148. appClass = GetApplicationClass(env);
  149. NULL_CHECK_RETURN_VALUE(appClass, -1);
  150. /*
  151. * PostJVMInit uses the class name as the application name for GUI purposes,
  152. * for example, on OSX this sets the application name in the menu bar for
  153. * both SWT and JavaFX. So we\'ll pass the actual application class here
  154. * instead of mainClass as that may be a launcher or helper class instead
  155. * of the application class.
  156. */
  157. // 加载main() 方法前执行初始化
  158. PostJVMInit(env, appClass, vm);
  159. CHECK_EXCEPTION_LEAVE(1);
  160. /*
  161. * The LoadMainClass not only loads the main class, it will also ensure
  162. * that the main method\'s signature is correct, therefore further checking
  163. * is not required. The main method is invoked here so that extraneous java
  164. * stacks are not in the application stack trace.
  165. */
  166. // 重点3:执行 main(args[]) java方法
  167. // 获取main()方法id, main(String[] args)
  168. mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
  169. "([Ljava/lang/String;)V");
  170. CHECK_EXCEPTION_NULL_LEAVE(mainID);
  171. /* Build platform specific argument array */
  172. // 构建args[] 参数
  173. mainArgs = CreateApplicationArgs(env, argv, argc);
  174. CHECK_EXCEPTION_NULL_LEAVE(mainArgs);
  175. /* Invoke main method. */
  176. // 调用java实现的main()方法
  177. // XX:: 重要实现
  178. (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
  179. /*
  180. * The launcher\'s exit code (in the absence of calls to
  181. * System.exit) will be non-zero if main threw an exception.
  182. */
  183. ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1;
  184. LEAVE();
  185. }

  JVM的初始化,我们在上篇系列文章中已窥得简要。这篇,我们就以 *env 作为入口进行。因为jvm初始化完成后,就会给 *env 的赋值。

 

  而,加载main()方法,最核心的就是上面最后几行:

  1. // 获取main()方法id, main(String[] args)
  2. mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
  3. "([Ljava/lang/String;)V");
  4. CHECK_EXCEPTION_NULL_LEAVE(mainID);
  5. /* Build platform specific argument array */
  6. // 构建args[] 参数
  7. mainArgs = CreateApplicationArgs(env, argv, argc);
  8. CHECK_EXCEPTION_NULL_LEAVE(mainArgs);
  9. /* Invoke main method. */
  10. // 调用java实现的main()方法
  11. // XX:: 重要实现
  12. (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
  13. /*
  14. * The launcher\'s exit code (in the absence of calls to
  15. * System.exit) will be non-zero if main threw an exception.
  16. */
  17. ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1;

  很明显,我们的目的就是看jvm如何找到main()方法,这也是执行main()逻辑的第一步工作。下面来细聊下,它使用的是 (*env)->GetStaticMethodID(), 而这个方法,在上一节中,我们可以看到其实现为:jni_GetStaticMethodID 。 所以,知道这个 jni_GetStaticMethodID 的实现就知道了如何查找java静态方法了。

  1. // share/vm/prims/jni.cpp
  2. JNI_ENTRY(jmethodID, jni_GetStaticMethodID(JNIEnv *env, jclass clazz,
  3. const char *name, const char *sig))
  4. JNIWrapper("GetStaticMethodID");
  5. #ifndef USDT2
  6. DTRACE_PROBE4(hotspot_jni, GetStaticMethodID__entry, env, clazz, name, sig);
  7. #else /* USDT2 */
  8. HOTSPOT_JNI_GETSTATICMETHODID_ENTRY(
  9. env, (char *) clazz, (char *) name, (char *)sig);
  10. #endif /* USDT2 */
  11. jmethodID ret = get_method_id(env, clazz, name, sig, true, thread);
  12. #ifndef USDT2
  13. DTRACE_PROBE1(hotspot_jni, GetStaticMethodID__return, ret);
  14. #else /* USDT2 */
  15. HOTSPOT_JNI_GETSTATICMETHODID_RETURN(
  16. (uintptr_t) ret);
  17. #endif /* USDT2 */
  18. return ret;
  19. JNI_END

  我们通过这个实现,能看到什么呢?好像什么也看不懂。实际上是因为,其中有太多的宏定义了,要想读懂这代码,必须将宏定义展开。而这些宏,基本都是是在 interfaceSupport.hpp 中定义的。

  下面我们来看下 JNI_ENTRY|JNI_END 的定义拆解:

  1. // share/vm/runtime/interfaceSupport.hpp
  2. // JNI_ENTRY 的定义,又依赖于 JNI_ENTRY_NO_PRESERVE 的定义
  3. #define JNI_ENTRY(result_type, header) \
  4. JNI_ENTRY_NO_PRESERVE(result_type, header) \
  5. WeakPreserveExceptionMark __wem(thread);
  6. // JNI_ENTRY_NO_PRESERVE 的定义,又依赖于 VM_ENTRY_BASE 的定义
  7. #define JNI_ENTRY_NO_PRESERVE(result_type, header) \
  8. extern "C" { \
  9. result_type JNICALL header { \
  10. JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
  11. assert( !VerifyJNIEnvThread || (thread == Thread::current()), "JNIEnv is only valid in same thread"); \
  12. ThreadInVMfromNative __tiv(thread); \
  13. debug_only(VMNativeEntryWrapper __vew;) \
  14. VM_ENTRY_BASE(result_type, header, thread)
  15. // VM_ENTRY_BASE 的定义
  16. #define VM_ENTRY_BASE(result_type, header, thread) \
  17. TRACE_CALL(result_type, header) \
  18. HandleMarkCleaner __hm(thread); \
  19. Thread* THREAD = thread; \
  20. os::verify_stack_alignment(); \
  21. /* begin of body */
  22.  
  23. // Close the routine and the extern "C"
  24. #define JNI_END } }

  此时,如上的函数实现可以转换为:

  1. extern "C" {
  2. jmethodID JNICALL header {
  3. JavaThread* thread=JavaThread::thread_from_jni_environment(env);
  4. assert( !VerifyJNIEnvThread || (thread == Thread::current()), "JNIEnv is only valid in same thread");
  5. ThreadInVMfromNative __tiv(thread);
  6. debug_only(VMNativeEntryWrapper __vew;)
  7. TRACE_CALL(jmethodID, jni_GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig))
  8. HandleMarkCleaner __hm(thread);
  9. Thread* THREAD = thread;
  10. os::verify_stack_alignment();
  11. WeakPreserveExceptionMark __wem(thread);
  12. // 默认为空
  13. JNIWrapper("GetStaticMethodID");
  14. #ifndef USDT2
  15. DTRACE_PROBE4(hotspot_jni, GetStaticMethodID__entry, env, clazz, name, sig);
  16. #else /* USDT2 */
  17. // 默认为空, 在 hotspot/src/share/vm/utilities/dtrace_usdt2_disabled.hpp 中定义
  18. HOTSPOT_JNI_GETSTATICMETHODID_ENTRY(
  19. env, (char *) clazz, (char *) name, (char *)sig);
  20. #endif /* USDT2 */
  21. // 核心查找方法
  22. jmethodID ret = get_method_id(env, clazz, name, sig, true, thread);
  23. #ifndef USDT2
  24. DTRACE_PROBE1(hotspot_jni, GetStaticMethodID__return, ret);
  25. #else /* USDT2 */
  26. // 默认为空
  27. HOTSPOT_JNI_GETSTATICMETHODID_RETURN(
  28. (uintptr_t) ret);
  29. #endif /* USDT2 */
  30. return ret;
  31. } }

  经过这一层层的宏展开,工作就变得清晰起来,重点在于 get_method_id() 了。

  1. // jni.cpp 根据方法签名,找到方法id
  2. static jmethodID get_method_id(JNIEnv *env, jclass clazz, const char *name_str,
  3. const char *sig, bool is_static, TRAPS) {
  4. // %%%% This code should probably just call into a method in the LinkResolver
  5. //
  6. // The class should have been loaded (we have an instance of the class
  7. // passed in) so the method and signature should already be in the symbol
  8. // table. If they\'re not there, the method doesn\'t exist.
  9. const char *name_to_probe = (name_str == NULL)
  10. ? vmSymbols::object_initializer_name()->as_C_string()
  11. : name_str;
  12. TempNewSymbol name = SymbolTable::probe(name_to_probe, (int)strlen(name_to_probe));
  13. // sig如: "([Ljava/lang/String;)V"
  14. TempNewSymbol signature = SymbolTable::probe(sig, (int)strlen(sig));
  15. if (name == NULL || signature == NULL) {
  16. THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), name_str);
  17. }
  18. // Throw a NoSuchMethodError exception if we have an instance of a
  19. // primitive java.lang.Class
  20. if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(clazz))) {
  21. THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), name_str);
  22. }
  23. // 初始化类实例
  24. KlassHandle klass(THREAD,
  25. java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)));
  26. // Make sure class is linked and initialized before handing id\'s out to
  27. // Method*s.
  28. klass()->initialize(CHECK_NULL);
  29. Method* m;
  30. // "main"
  31. // "<init>" "<clinit>"
  32. if (name == vmSymbols::object_initializer_name() ||
  33. name == vmSymbols::class_initializer_name()) {
  34. // Never search superclasses for constructors
  35. if (klass->oop_is_instance()) {
  36. m = InstanceKlass::cast(klass())->find_method(name, signature);
  37. } else {
  38. m = NULL;
  39. }
  40. } else {
  41. // 只是在本类中进行方法id查找
  42. m = klass->lookup_method(name, signature);
  43. if (m == NULL && klass->oop_is_instance()) {
  44. m = InstanceKlass::cast(klass())->lookup_method_in_ordered_interfaces(name, signature);
  45. }
  46. }
  47. if (m == NULL || (m->is_static() != is_static)) {
  48. THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), name_str);
  49. }
  50. // 返回id
  51. return m->jmethod_id();
  52. }
  53. // share/vm/oops/klass.cpp
  54. public:
  55. Method* lookup_method(Symbol* name, Symbol* signature) const {
  56. return uncached_lookup_method(name, signature);
  57. }
  58. Method* Klass::uncached_lookup_method(Symbol* name, Symbol* signature) const {
  59. #ifdef ASSERT
  60. tty->print_cr("Error: uncached_lookup_method called on a klass oop."
  61. " Likely error: reflection method does not correctly"
  62. " wrap return value in a mirror object.");
  63. #endif
  64. ShouldNotReachHere();
  65. return NULL;
  66. }
  67. // oops/method.hpp
  68. // Get this method\'s jmethodID -- allocate if it doesn\'t exist
  69. jmethodID jmethod_id() {
  70. methodHandle this_h(this);
  71. return InstanceKlass::get_jmethod_id(method_holder(), this_h);
  72. }
  73. // oops/instanceKlass.cpp
  74. // Lookup or create a jmethodID.
  75. // This code is called by the VMThread and JavaThreads so the
  76. // locking has to be done very carefully to avoid deadlocks
  77. // and/or other cache consistency problems.
  78. //
  79. jmethodID InstanceKlass::get_jmethod_id(instanceKlassHandle ik_h, methodHandle method_h) {
  80. size_t idnum = (size_t)method_h->method_idnum();
  81. jmethodID* jmeths = ik_h->methods_jmethod_ids_acquire();
  82. size_t length = 0;
  83. jmethodID id = NULL;
  84. // We use a double-check locking idiom here because this cache is
  85. // performance sensitive. In the normal system, this cache only
  86. // transitions from NULL to non-NULL which is safe because we use
  87. // release_set_methods_jmethod_ids() to advertise the new cache.
  88. // A partially constructed cache should never be seen by a racing
  89. // thread. We also use release_store_ptr() to save a new jmethodID
  90. // in the cache so a partially constructed jmethodID should never be
  91. // seen either. Cache reads of existing jmethodIDs proceed without a
  92. // lock, but cache writes of a new jmethodID requires uniqueness and
  93. // creation of the cache itself requires no leaks so a lock is
  94. // generally acquired in those two cases.
  95. //
  96. // If the RedefineClasses() API has been used, then this cache can
  97. // grow and we\'ll have transitions from non-NULL to bigger non-NULL.
  98. // Cache creation requires no leaks and we require safety between all
  99. // cache accesses and freeing of the old cache so a lock is generally
  100. // acquired when the RedefineClasses() API has been used.
  101.  
  102. if (jmeths != NULL) {
  103. // the cache already exists
  104. if (!ik_h->idnum_can_increment()) {
  105. // the cache can\'t grow so we can just get the current values
  106. get_jmethod_id_length_value(jmeths, idnum, &length, &id);
  107. } else {
  108. // cache can grow so we have to be more careful
  109. if (Threads::number_of_threads() == 0 ||
  110. SafepointSynchronize::is_at_safepoint()) {
  111. // we\'re single threaded or at a safepoint - no locking needed
  112. get_jmethod_id_length_value(jmeths, idnum, &length, &id);
  113. } else {
  114. MutexLocker ml(JmethodIdCreation_lock);
  115. get_jmethod_id_length_value(jmeths, idnum, &length, &id);
  116. }
  117. }
  118. }
  119. // implied else:
  120. // we need to allocate a cache so default length and id values are good
  121.  
  122. if (jmeths == NULL || // no cache yet
  123. length <= idnum || // cache is too short
  124. id == NULL) { // cache doesn\'t contain entry
  125. // This function can be called by the VMThread so we have to do all
  126. // things that might block on a safepoint before grabbing the lock.
  127. // Otherwise, we can deadlock with the VMThread or have a cache
  128. // consistency issue. These vars keep track of what we might have
  129. // to free after the lock is dropped.
  130. jmethodID to_dealloc_id = NULL;
  131. jmethodID* to_dealloc_jmeths = NULL;
  132. // may not allocate new_jmeths or use it if we allocate it
  133. jmethodID* new_jmeths = NULL;
  134. if (length <= idnum) {
  135. // allocate a new cache that might be used
  136. size_t size = MAX2(idnum+1, (size_t)ik_h->idnum_allocated_count());
  137. new_jmeths = NEW_C_HEAP_ARRAY(jmethodID, size+1, mtClass);
  138. memset(new_jmeths, 0, (size+1)*sizeof(jmethodID));
  139. // cache size is stored in element[0], other elements offset by one
  140. new_jmeths[0] = (jmethodID)size;
  141. }
  142. // allocate a new jmethodID that might be used
  143. jmethodID new_id = NULL;
  144. if (method_h->is_old() && !method_h->is_obsolete()) {
  145. // The method passed in is old (but not obsolete), we need to use the current version
  146. Method* current_method = ik_h->method_with_idnum((int)idnum);
  147. assert(current_method != NULL, "old and but not obsolete, so should exist");
  148. new_id = Method::make_jmethod_id(ik_h->class_loader_data(), current_method);
  149. } else {
  150. // It is the current version of the method or an obsolete method,
  151. // use the version passed in
  152. new_id = Method::make_jmethod_id(ik_h->class_loader_data(), method_h());
  153. }
  154. if (Threads::number_of_threads() == 0 ||
  155. SafepointSynchronize::is_at_safepoint()) {
  156. // we\'re single threaded or at a safepoint - no locking needed
  157. id = get_jmethod_id_fetch_or_update(ik_h, idnum, new_id, new_jmeths,
  158. &to_dealloc_id, &to_dealloc_jmeths);
  159. } else {
  160. MutexLocker ml(JmethodIdCreation_lock);
  161. id = get_jmethod_id_fetch_or_update(ik_h, idnum, new_id, new_jmeths,
  162. &to_dealloc_id, &to_dealloc_jmeths);
  163. }
  164. // The lock has been dropped so we can free resources.
  165. // Free up either the old cache or the new cache if we allocated one.
  166. if (to_dealloc_jmeths != NULL) {
  167. FreeHeap(to_dealloc_jmeths);
  168. }
  169. // free up the new ID since it wasn\'t needed
  170. if (to_dealloc_id != NULL) {
  171. Method::destroy_jmethod_id(ik_h->class_loader_data(), to_dealloc_id);
  172. }
  173. }
  174. return id;
  175. }

  查找 methodID的实现就挖到这里吧,拆不下去了,尴尬。

  但有一点很明了,就是查找methodID是在mainClass实例中进行的。那么,mainClass又是如何查找到的,我们需要看下。这个要从 LoadMainClass()说起。

 

  上一节我们找到了方法id, 但却未找到类。所以,得重头开始再来。

  1. /*
  2. * Loads a class and verifies that the main class is present and it is ok to
  3. * call it for more details refer to the java implementation.
  4. */
  5. static jclass
  6. LoadMainClass(JNIEnv *env, int mode, char *name)
  7. {
  8. jmethodID mid;
  9. jstring str;
  10. jobject result;
  11. jlong start, end;
  12. // sun/launcher/LauncherHelper
  13. jclass cls = GetLauncherHelperClass(env);
  14. NULL_CHECK0(cls);
  15. if (JLI_IsTraceLauncher()) {
  16. start = CounterGet();
  17. }
  18. // checkAndLoadMain(String) 方法作为中间main()调用
  19. NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls,
  20. "checkAndLoadMain",
  21. "(ZILjava/lang/String;)Ljava/lang/Class;"));
  22. str = NewPlatformString(env, name);
  23. CHECK_JNI_RETURN_0(
  24. result = (*env)->CallStaticObjectMethod(
  25. env, cls, mid, USE_STDERR, mode, str));
  26. if (JLI_IsTraceLauncher()) {
  27. end = CounterGet();
  28. printf("%ld micro seconds to load main class\n",
  29. (long)(jint)Counter2Micros(end-start));
  30. printf("----%s----\n", JLDEBUG_ENV_ENTRY);
  31. }
  32. return (jclass)result;
  33. }
  34. jclass
  35. GetLauncherHelperClass(JNIEnv *env)
  36. {
  37. if (helperClass == NULL) {
  38. // 查找 helplerClass, 并缓存
  39. NULL_CHECK0(helperClass = FindBootStrapClass(env,
  40. "sun/launcher/LauncherHelper"));
  41. }
  42. return helperClass;
  43. }
  44. // solaris/bin/java_md_common.c
  45. // 查找启动类
  46. jclass
  47. FindBootStrapClass(JNIEnv *env, const char* classname)
  48. {
  49. // 先找到jvm的 JVM_FindClassFromBootLoader 函数地址,然后调用即可
  50. if (findBootClass == NULL) {
  51. findBootClass = (FindClassFromBootLoader_t *)dlsym(RTLD_DEFAULT,
  52. "JVM_FindClassFromBootLoader");
  53. if (findBootClass == NULL) {
  54. JLI_ReportErrorMessage(DLL_ERROR4,
  55. "JVM_FindClassFromBootLoader");
  56. return NULL;
  57. }
  58. }
  59. return findBootClass(env, classname);
  60. }

  具体怎么调用,我们略去不说。但如何查找启动类,可以一起来看看。即 JVM_FindClassFromBootLoader。

  1. // jvm.cpp
  2. // Returns a class loaded by the bootstrap class loader; or null
  3. // if not found. ClassNotFoundException is not thrown.
  4. //
  5. // Rationale behind JVM_FindClassFromBootLoader
  6. // a> JVM_FindClassFromClassLoader was never exported in the export tables.
  7. // b> because of (a) java.dll has a direct dependecy on the unexported
  8. // private symbol "_JVM_FindClassFromClassLoader@20".
  9. // c> the launcher cannot use the private symbol as it dynamically opens
  10. // the entry point, so if something changes, the launcher will fail
  11. // unexpectedly at runtime, it is safest for the launcher to dlopen a
  12. // stable exported interface.
  13. // d> re-exporting JVM_FindClassFromClassLoader as public, will cause its
  14. // signature to change from _JVM_FindClassFromClassLoader@20 to
  15. // JVM_FindClassFromClassLoader and will not be backward compatible
  16. // with older JDKs.
  17. // Thus a public/stable exported entry point is the right solution,
  18. // public here means public in linker semantics, and is exported only
  19. // to the JDK, and is not intended to be a public API.
  20. JVM_ENTRY(jclass, JVM_FindClassFromBootLoader(JNIEnv* env,
  21. const char* name))
  22. JVMWrapper2("JVM_FindClassFromBootLoader %s", name);
  23. // Java libraries should ensure that name is never null...
  24. // 类名称最长不超过65535
  25. if (name == NULL || (int)strlen(name) > Symbol::max_length()) {
  26. // It\'s impossible to create this class; the name cannot fit
  27. // into the constant pool.
  28. return NULL;
  29. }
  30. // 常量池检查
  31. // 创建启动类实例
  32. TempNewSymbol h_name = SymbolTable::new_symbol(name, CHECK_NULL);
  33. Klass* k = SystemDictionary::resolve_or_null(h_name, CHECK_NULL);
  34. if (k == NULL) {
  35. return NULL;
  36. }
  37. if (TraceClassResolution) {
  38. trace_class_resolution(k);
  39. }
  40. // 创建jclass版本实例返回
  41. return (jclass) JNIHandles::make_local(env, k->java_mirror());
  42. JVM_END

  整个方法定义,除去各复杂的宏定义,基本还是逻辑比较清晰的。 分三步走:1. 从常量池拿类名信息;2. 查找类信息实例化Klass;3. 转换为jclass返回。

 

  在查找启动类时,看到有常量池的处理,这也是每个类的初始化时必须的过程,所以来看看常量池的使用吧。

  1. // share/vm/classfile/symbolTable.hpp
  2. // Symbol creation
  3. static Symbol* new_symbol(const char* utf8_buffer, int length, TRAPS) {
  4. assert(utf8_buffer != NULL, "just checking");
  5. return lookup(utf8_buffer, length, THREAD);
  6. }
  7. // symbolTable.cpp
  8. // We take care not to be blocking while holding the
  9. // SymbolTable_lock. Otherwise, the system might deadlock, since the
  10. // symboltable is used during compilation (VM_thread) The lock free
  11. // synchronization is simplified by the fact that we do not delete
  12. // entries in the symbol table during normal execution (only during
  13. // safepoints).
  14. Symbol* SymbolTable::lookup(const char* name, int len, TRAPS) {
  15. unsigned int hashValue = hash_symbol(name, len);
  16. int index = the_table()->hash_to_index(hashValue);
  17. Symbol* s = the_table()->lookup(index, name, len, hashValue);
  18. // Found
  19. if (s != NULL) return s;
  20. // 上锁添加常量池
  21. // Grab SymbolTable_lock first.
  22. MutexLocker ml(SymbolTable_lock, THREAD);
  23. // Otherwise, add to symbol to table
  24. return the_table()->basic_add(index, (u1*)name, len, hashValue, true, CHECK_NULL);
  25. }
  26. // This version of basic_add adds symbols in batch from the constant pool
  27. // parsing.
  28. bool SymbolTable::basic_add(ClassLoaderData* loader_data, constantPoolHandle cp,
  29. int names_count,
  30. const char** names, int* lengths,
  31. int* cp_indices, unsigned int* hashValues,
  32. TRAPS) {
  33. // Check symbol names are not too long. If any are too long, don\'t add any.
  34. for (int i = 0; i< names_count; i++) {
  35. if (lengths[i] > Symbol::max_length()) {
  36. THROW_MSG_0(vmSymbols::java_lang_InternalError(),
  37. "name is too long to represent");
  38. }
  39. }
  40. // Cannot hit a safepoint in this function because the "this" pointer can move.
  41. No_Safepoint_Verifier nsv;
  42. for (int i=0; i<names_count; i++) {
  43. // Check if the symbol table has been rehashed, if so, need to recalculate
  44. // the hash value.
  45. unsigned int hashValue;
  46. if (use_alternate_hashcode()) {
  47. hashValue = hash_symbol(names[i], lengths[i]);
  48. } else {
  49. hashValue = hashValues[i];
  50. }
  51. // Since look-up was done lock-free, we need to check if another
  52. // thread beat us in the race to insert the symbol.
  53. int index = hash_to_index(hashValue);
  54. Symbol* test = lookup(index, names[i], lengths[i], hashValue);
  55. if (test != NULL) {
  56. // A race occurred and another thread introduced the symbol, this one
  57. // will be dropped and collected. Use test instead.
  58. cp->symbol_at_put(cp_indices[i], test);
  59. assert(test->refcount() != 0, "lookup should have incremented the count");
  60. } else {
  61. // Create a new symbol. The null class loader is never unloaded so these
  62. // are allocated specially in a permanent arena.
  63. bool c_heap = !loader_data->is_the_null_class_loader_data();
  64. Symbol* sym = allocate_symbol((const u1*)names[i], lengths[i], c_heap, CHECK_(false));
  65. assert(sym->equals(names[i], lengths[i]), "symbol must be properly initialized"); // why wouldn\'t it be???
  66. HashtableEntry<Symbol*, mtSymbol>* entry = new_entry(hashValue, sym);
  67. add_entry(index, entry);
  68. cp->symbol_at_put(cp_indices[i], sym);
  69. }
  70. }
  71. return true;
  72. }

  通过hash的方式,将字符串添加到常量池中。下一次进行字符串获取时,也就直接从常量池中获取即可。hash作为查找最快的方式,非常有效。因为类信息本身就会反复使用,所以使用常量池或者缓存的方式保存,再好不过。

 

  经过常量池处理后,进行实例查找和创建。有点复杂,有可能还涉及到java代码的交互。我们只看大概。

  1. // share/vm/classfile/systemDictionary.cpp
  2. Klass* SystemDictionary::resolve_or_null(Symbol* class_name, TRAPS) {
  3. return resolve_or_null(class_name, Handle(), Handle(), THREAD);
  4. }
  5. // Forwards to resolve_instance_class_or_null
  6. Klass* SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) {
  7. assert(!THREAD->is_Compiler_thread(),
  8. err_msg("can not load classes with compiler thread: class=%s, classloader=%s",
  9. class_name->as_C_string(),
  10. class_loader.is_null() ? "null" : class_loader->klass()->name()->as_C_string()));
  11. if (FieldType::is_array(class_name)) {
  12. return resolve_array_class_or_null(class_name, class_loader, protection_domain, CHECK_NULL);
  13. } else if (FieldType::is_obj(class_name)) {
  14. ResourceMark rm(THREAD);
  15. // Ignore wrapping L and ;.
  16. // 类的命名,一定是 Ljava/lang/String;
  17. TempNewSymbol name = SymbolTable::new_symbol(class_name->as_C_string() + 1,
  18. class_name->utf8_length() - 2, CHECK_NULL);
  19. return resolve_instance_class_or_null(name, class_loader, protection_domain, CHECK_NULL);
  20. } else {
  21. return resolve_instance_class_or_null(class_name, class_loader, protection_domain, CHECK_NULL);
  22. }
  23. }
  24. Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
  25. Handle class_loader,
  26. Handle protection_domain,
  27. TRAPS) {
  28. assert(name != NULL && !FieldType::is_array(name) &&
  29. !FieldType::is_obj(name), "invalid class name");
  30. Ticks class_load_start_time = Ticks::now();
  31. // UseNewReflection
  32. // Fix for 4474172; see evaluation for more details
  33. class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
  34. ClassLoaderData *loader_data = register_loader(class_loader, CHECK_NULL);
  35. // Do lookup to see if class already exist and the protection domain
  36. // has the right access
  37. // This call uses find which checks protection domain already matches
  38. // All subsequent calls use find_class, and set has_loaded_class so that
  39. // before we return a result we call out to java to check for valid protection domain
  40. // to allow returning the Klass* and add it to the pd_set if it is valid
  41. unsigned int d_hash = dictionary()->compute_hash(name, loader_data);
  42. int d_index = dictionary()->hash_to_index(d_hash);
  43. Klass* probe = dictionary()->find(d_index, d_hash, name, loader_data,
  44. protection_domain, THREAD);
  45. if (probe != NULL) return probe;
  46. // Non-bootstrap class loaders will call out to class loader and
  47. // define via jvm/jni_DefineClass which will acquire the
  48. // class loader object lock to protect against multiple threads
  49. // defining the class in parallel by accident.
  50. // This lock must be acquired here so the waiter will find
  51. // any successful result in the SystemDictionary and not attempt
  52. // the define
  53. // ParallelCapable Classloaders and the bootstrap classloader,
  54. // or all classloaders with UnsyncloadClass do not acquire lock here
  55. bool DoObjectLock = true;
  56. if (is_parallelCapable(class_loader)) {
  57. DoObjectLock = false;
  58. }
  59. unsigned int p_hash = placeholders()->compute_hash(name, loader_data);
  60. int p_index = placeholders()->hash_to_index(p_hash);
  61. // Class is not in SystemDictionary so we have to do loading.
  62. // Make sure we are synchronized on the class loader before we proceed
  63. Handle lockObject = compute_loader_lock_object(class_loader, THREAD);
  64. check_loader_lock_contention(lockObject, THREAD);
  65. ObjectLocker ol(lockObject, THREAD, DoObjectLock);
  66. // Check again (after locking) if class already exist in SystemDictionary
  67. bool class_has_been_loaded = false;
  68. bool super_load_in_progress = false;
  69. bool havesupername = false;
  70. instanceKlassHandle k;
  71. PlaceholderEntry* placeholder;
  72. Symbol* superclassname = NULL;
  73. {
  74. MutexLocker mu(SystemDictionary_lock, THREAD);
  75. Klass* check = find_class(d_index, d_hash, name, loader_data);
  76. if (check != NULL) {
  77. // Klass is already loaded, so just return it
  78. class_has_been_loaded = true;
  79. k = instanceKlassHandle(THREAD, check);
  80. } else {
  81. placeholder = placeholders()->get_entry(p_index, p_hash, name, loader_data);
  82. if (placeholder && placeholder->super_load_in_progress()) {
  83. super_load_in_progress = true;
  84. if (placeholder->havesupername() == true) {
  85. superclassname = placeholder->supername();
  86. havesupername = true;
  87. }
  88. }
  89. }
  90. }
  91. // If the class is in the placeholder table, class loading is in progress
  92. if (super_load_in_progress && havesupername==true) {
  93. k = SystemDictionary::handle_parallel_super_load(name, superclassname,
  94. class_loader, protection_domain, lockObject, THREAD);
  95. if (HAS_PENDING_EXCEPTION) {
  96. return NULL;
  97. }
  98. if (!k.is_null()) {
  99. class_has_been_loaded = true;
  100. }
  101. }
  102. bool throw_circularity_error = false;
  103. if (!class_has_been_loaded) {
  104. bool load_instance_added = false;
  105. // add placeholder entry to record loading instance class
  106. // Five cases:
  107. // All cases need to prevent modifying bootclasssearchpath
  108. // in parallel with a classload of same classname
  109. // Redefineclasses uses existence of the placeholder for the duration
  110. // of the class load to prevent concurrent redefinition of not completely
  111. // defined classes.
  112. // case 1. traditional classloaders that rely on the classloader object lock
  113. // - no other need for LOAD_INSTANCE
  114. // case 2. traditional classloaders that break the classloader object lock
  115. // as a deadlock workaround. Detection of this case requires that
  116. // this check is done while holding the classloader object lock,
  117. // and that lock is still held when calling classloader\'s loadClass.
  118. // For these classloaders, we ensure that the first requestor
  119. // completes the load and other requestors wait for completion.
  120. // case 3. UnsyncloadClass - don\'t use objectLocker
  121. // With this flag, we allow parallel classloading of a
  122. // class/classloader pair
  123. // case4. Bootstrap classloader - don\'t own objectLocker
  124. // This classloader supports parallelism at the classloader level,
  125. // but only allows a single load of a class/classloader pair.
  126. // No performance benefit and no deadlock issues.
  127. // case 5. parallelCapable user level classloaders - without objectLocker
  128. // Allow parallel classloading of a class/classloader pair
  129. {
  130. MutexLocker mu(SystemDictionary_lock, THREAD);
  131. if (class_loader.is_null() || !is_parallelCapable(class_loader)) {
  132. PlaceholderEntry* oldprobe = placeholders()->get_entry(p_index, p_hash, name, loader_data);
  133. if (oldprobe) {
  134. // only need check_seen_thread once, not on each loop
  135. // 6341374 java/lang/Instrument with -Xcomp
  136. if (oldprobe->check_seen_thread(THREAD, PlaceholderTable::LOAD_INSTANCE)) {
  137. throw_circularity_error = true;
  138. } else {
  139. // case 1: traditional: should never see load_in_progress.
  140. while (!class_has_been_loaded && oldprobe && oldprobe->instance_load_in_progress()) {
  141. // case 4: bootstrap classloader: prevent futile classloading,
  142. // wait on first requestor
  143. if (class_loader.is_null()) {
  144. SystemDictionary_lock->wait();
  145. } else {
  146. // case 2: traditional with broken classloader lock. wait on first
  147. // requestor.
  148. double_lock_wait(lockObject, THREAD);
  149. }
  150. // Check if classloading completed while we were waiting
  151. Klass* check = find_class(d_index, d_hash, name, loader_data);
  152. if (check != NULL) {
  153. // Klass is already loaded, so just return it
  154. k = instanceKlassHandle(THREAD, check);
  155. class_has_been_loaded = true;
  156. }
  157. // check if other thread failed to load and cleaned up
  158. oldprobe = placeholders()->get_entry(p_index, p_hash, name, loader_data);
  159. }
  160. }
  161. }
  162. }
  163. // All cases: add LOAD_INSTANCE holding SystemDictionary_lock
  164. // case 3: UnsyncloadClass || case 5: parallelCapable: allow competing threads to try
  165. // LOAD_INSTANCE in parallel
  166.  
  167. if (!throw_circularity_error && !class_has_been_loaded) {
  168. PlaceholderEntry* newprobe = placeholders()->find_and_add(p_index, p_hash, name, loader_data, PlaceholderTable::LOAD_INSTANCE, NULL, THREAD);
  169. load_instance_added = true;
  170. // For class loaders that do not acquire the classloader object lock,
  171. // if they did not catch another thread holding LOAD_INSTANCE,
  172. // need a check analogous to the acquire ObjectLocker/find_class
  173. // i.e. now that we hold the LOAD_INSTANCE token on loading this class/CL
  174. // one final check if the load has already completed
  175. // class loaders holding the ObjectLock shouldn\'t find the class here
  176. Klass* check = find_class(d_index, d_hash, name, loader_data);
  177. if (check != NULL) {
  178. // Klass is already loaded, so return it after checking/adding protection domain
  179. k = instanceKlassHandle(THREAD, check);
  180. class_has_been_loaded = true;
  181. }
  182. }
  183. }
  184. // must throw error outside of owning lock
  185. if (throw_circularity_error) {
  186. assert(!HAS_PENDING_EXCEPTION && load_instance_added == false,"circularity error cleanup");
  187. ResourceMark rm(THREAD);
  188. THROW_MSG_NULL(vmSymbols::java_lang_ClassCircularityError(), name->as_C_string());
  189. }
  190. if (!class_has_been_loaded) {
  191. // Do actual loading
  192. k = load_instance_class(name, class_loader, THREAD);
  193. // For UnsyncloadClass only
  194. // If they got a linkageError, check if a parallel class load succeeded.
  195. // If it did, then for bytecode resolution the specification requires
  196. // that we return the same result we did for the other thread, i.e. the
  197. // successfully loaded InstanceKlass
  198. // Should not get here for classloaders that support parallelism
  199. // with the new cleaner mechanism, even with AllowParallelDefineClass
  200. // Bootstrap goes through here to allow for an extra guarantee check
  201. if (UnsyncloadClass || (class_loader.is_null())) {
  202. if (k.is_null() && HAS_PENDING_EXCEPTION
  203. && PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) {
  204. MutexLocker mu(SystemDictionary_lock, THREAD);
  205. Klass* check = find_class(d_index, d_hash, name, loader_data);
  206. if (check != NULL) {
  207. // Klass is already loaded, so just use it
  208. k = instanceKlassHandle(THREAD, check);
  209. CLEAR_PENDING_EXCEPTION;
  210. guarantee((!class_loader.is_null()), "dup definition for bootstrap loader?");
  211. }
  212. }
  213. }
  214. // If everything was OK (no exceptions, no null return value), and
  215. // class_loader is NOT the defining loader, do a little more bookkeeping.
  216. if (!HAS_PENDING_EXCEPTION && !k.is_null() &&
  217. k->class_loader() != class_loader()) {
  218. check_constraints(d_index, d_hash, k, class_loader, false, THREAD);
  219. // Need to check for a PENDING_EXCEPTION again; check_constraints
  220. // can throw and doesn\'t use the CHECK macro.
  221. if (!HAS_PENDING_EXCEPTION) {
  222. { // Grabbing the Compile_lock prevents systemDictionary updates
  223. // during compilations.
  224. MutexLocker mu(Compile_lock, THREAD);
  225. update_dictionary(d_index, d_hash, p_index, p_hash,
  226. k, class_loader, THREAD);
  227. }
  228. if (JvmtiExport::should_post_class_load()) {
  229. Thread *thread = THREAD;
  230. assert(thread->is_Java_thread(), "thread->is_Java_thread()");
  231. JvmtiExport::post_class_load((JavaThread *) thread, k());
  232. }
  233. }
  234. }
  235. } // load_instance_class loop
  236.  
  237. if (HAS_PENDING_EXCEPTION) {
  238. // An exception, such as OOM could have happened at various places inside
  239. // load_instance_class. We might have partially initialized a shared class
  240. // and need to clean it up.
  241. if (class_loader.is_null()) {
  242. // In some cases k may be null. Let\'s find the shared class again.
  243. instanceKlassHandle ik(THREAD, find_shared_class(name));
  244. if (ik.not_null()) {
  245. if (ik->class_loader_data() == NULL) {
  246. // We didn\'t go as far as Klass::restore_unshareable_info(),
  247. // so nothing to clean up.
  248. } else {
  249. Klass *kk;
  250. {
  251. MutexLocker mu(SystemDictionary_lock, THREAD);
  252. kk = find_class(d_index, d_hash, name, ik->class_loader_data());
  253. }
  254. if (kk != NULL) {
  255. // No clean up is needed if the shared class has been entered
  256. // into system dictionary, as load_shared_class() won\'t be called
  257. // again.
  258. } else {
  259. // This must be done outside of the SystemDictionary_lock to
  260. // avoid deadlock.
  261. //
  262. // Note that Klass::restore_unshareable_info (called via
  263. // load_instance_class above) is also called outside
  264. // of SystemDictionary_lock. Other threads are blocked from
  265. // loading this class because they are waiting on the
  266. // SystemDictionary_lock until this thread removes
  267. // the placeholder below.
  268. //
  269. // This need to be re-thought when parallel-capable non-boot
  270. // classloaders are supported by CDS (today they\'re not).
  271. clean_up_shared_class(ik, class_loader, THREAD);
  272. }
  273. }
  274. }
  275. }
  276. }
  277. if (load_instance_added == true) {
  278. // clean up placeholder entries for LOAD_INSTANCE success or error
  279. // This brackets the SystemDictionary updates for both defining
  280. // and initiating loaders
  281. MutexLocker mu(SystemDictionary_lock, THREAD);
  282. placeholders()->find_and_remove(p_index, p_hash, name, loader_data, PlaceholderTable::LOAD_INSTANCE, THREAD);
  283. SystemDictionary_lock->notify_all();
  284. }
  285. }
  286. if (HAS_PENDING_EXCEPTION || k.is_null()) {
  287. return NULL;
  288. }
  289. post_class_load_event(class_load_start_time, k, class_loader);
  290. #ifdef ASSERT
  291. {
  292. ClassLoaderData* loader_data = k->class_loader_data();
  293. MutexLocker mu(SystemDictionary_lock, THREAD);
  294. Klass* kk = find_class(name, loader_data);
  295. assert(kk == k(), "should be present in dictionary");
  296. }
  297. #endif
  298.  
  299. // return if the protection domain in NULL
  300. if (protection_domain() == NULL) return k();
  301. // Check the protection domain has the right access
  302. {
  303. MutexLocker mu(SystemDictionary_lock, THREAD);
  304. // Note that we have an entry, and entries can be deleted only during GC,
  305. // so we cannot allow GC to occur while we\'re holding this entry.
  306. // We\'re using a No_Safepoint_Verifier to catch any place where we
  307. // might potentially do a GC at all.
  308. // Dictionary::do_unloading() asserts that classes in SD are only
  309. // unloaded at a safepoint. Anonymous classes are not in SD.
  310. No_Safepoint_Verifier nosafepoint;
  311. if (dictionary()->is_valid_protection_domain(d_index, d_hash, name,
  312. loader_data,
  313. protection_domain)) {
  314. return k();
  315. }
  316. }
  317. // Verify protection domain. If it fails an exception is thrown
  318. validate_protection_domain(k, class_loader, protection_domain, CHECK_NULL);
  319. return k();
  320. }

  有点复杂,空了细看吧。另外可以提一下的就是,每一次class的加载,都会附带一个锁的操作

  1. { MutexLocker mu(SystemDictionary_lock, THREAD); kk = find_class(d_index, d_hash, name, ik->class_loader_data()); }

  这种锁超出作用域后,就会调用析构方法,然后就会自动进行锁释放。这和很多的锁需要 lock() -> unlock() 到是省了一些事。

 

  JNIHandles::make_local(), 大概意思是将前面解析出来的 Klass 转换对应的 jclass , 而这其中又有很多弯弯绕。

  1. // share/vm/runtime/jniHandles.cpp
  2. jobject JNIHandles::make_local(JNIEnv* env, oop obj) {
  3. if (obj == NULL) {
  4. return NULL; // ignore null handles
  5. } else {
  6. JavaThread* thread = JavaThread::thread_from_jni_environment(env);
  7. assert(Universe::heap()->is_in_reserved(obj), "sanity check");
  8. return thread->active_handles()->allocate_handle(obj);
  9. }
  10. }
  11. jobject JNIHandleBlock::allocate_handle(oop obj) {
  12. assert(Universe::heap()->is_in_reserved(obj), "sanity check");
  13. if (_top == 0) {
  14. // This is the first allocation or the initial block got zapped when
  15. // entering a native function. If we have any following blocks they are
  16. // not valid anymore.
  17. for (JNIHandleBlock* current = _next; current != NULL;
  18. current = current->_next) {
  19. assert(current->_last == NULL, "only first block should have _last set");
  20. assert(current->_free_list == NULL,
  21. "only first block should have _free_list set");
  22. current->_top = 0;
  23. if (ZapJNIHandleArea) current->zap();
  24. }
  25. // Clear initial block
  26. _free_list = NULL;
  27. _allocate_before_rebuild = 0;
  28. _last = this;
  29. if (ZapJNIHandleArea) zap();
  30. }
  31. // Try last block
  32. if (_last->_top < block_size_in_oops) {
  33. oop* handle = &(_last->_handles)[_last->_top++];
  34. *handle = obj;
  35. // 出口1
  36. return (jobject) handle;
  37. }
  38. // Try free list
  39. if (_free_list != NULL) {
  40. oop* handle = _free_list;
  41. _free_list = (oop*) *_free_list;
  42. *handle = obj;
  43. // 出口2
  44. return (jobject) handle;
  45. }
  46. // Check if unused block follow last
  47. if (_last->_next != NULL) {
  48. // update last and retry
  49. _last = _last->_next;
  50. return allocate_handle(obj);
  51. }
  52. // No space available, we have to rebuild free list or expand
  53. if (_allocate_before_rebuild == 0) {
  54. rebuild_free_list(); // updates _allocate_before_rebuild counter
  55. } else {
  56. // Append new block
  57. Thread* thread = Thread::current();
  58. Handle obj_handle(thread, obj);
  59. // This can block, so we need to preserve obj accross call.
  60. _last->_next = JNIHandleBlock::allocate_block(thread);
  61. _last = _last->_next;
  62. _allocate_before_rebuild--;
  63. obj = obj_handle();
  64. }
  65. return allocate_handle(obj); // retry
  66. }

  主要就是一个类型的转换,或者包装Kclass 以便可以操作更多,细节自行阅读。

 

       本文着重讲解了jvm对java类的查找,以及对类方法的查找实现。而且看起来,实现得挺复杂挺难的样子。

       然而,我们单就对一个类的查找方法的查找而言,应该是很简单的。而且两场景相似度也很高,只是一个入参是类名,另一个是方法签名。比如,对类的查找,无外乎一个hash数据结构的存取实现而已。只是在对类的初始过程,需要保证线程安全而已。而对于方法的查找,则可能更简单,因为方法毕竟有限,不如类来得多。甚至可能就是一个链表搞定,通过遍历签名即可得到方法id。

       实际上,当我们提出一个问题时,往往就已经将事情简单化了,或许已关系场景本身的初衷。因为,像jvm这种高难度玩意,需要极高的理论基础,设计能力,极广的知识面,以及超高的实现能力。因为,它本身的场景,就是提供各种不确定性。我等,只是做个吃瓜群众罢了。

       不过幸好,至少我们可以验证一些猜想,没有虚妄。至少会以为,抽丝剥茧之后的,我们都会。

       

版权声明:本文为yougewe原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/yougewe/p/14426936.html