成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

JVM(Java Virtual Machine)源碼分析-類加載場景實例分析

開發 后端
JVM是Java Virtual Machine(Java虛擬機)的縮寫,JVM是一種用于計算設備的規范,它是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現的。 引入Java語言虛擬機后,Java語言在不同平臺上運行時不需要重新編譯。Java語言使用Java虛擬機屏蔽了與具體平臺相關的信息,使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就可以在多種平臺上不加修改地運行。

JVM是Java Virtual Machine(Java虛擬機)的縮寫,JVM是一種用于計算設備的規范,它是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現的。 引入Java語言虛擬機后,Java語言在不同平臺上運行時不需要重新編譯。Java語言使用Java虛擬機屏蔽了與具體平臺相關的信息,使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就可以在多種平臺上不加修改地運行。

本篇就給大家分析類加載場景,希望能對你有所幫助。

 A類調用B類的靜態方法,除了加載B類,但是B類的一個未被調用的方法間接使用到的C類卻也被加載了,這個有意思的場景來自一個提問:方法中使用的類型為何在未調用時嘗試加載?。

場景如下:

  1. public class Main { 
  2.     static { 
  3.         System.out.println("Main static block"); 
  4.     } 
  5.  
  6.     public static void main(String[] args) { 
  7.         Helper.staticMethod(); 
  8.     } 
  9.  
  10. public class Helper { 
  11.     static { 
  12.         System.out.println("Helper static block"); 
  13.     } 
  14.  
  15.     public static void staticMethod() { 
  16.         System.out.println("Helper#staticMethod"); 
  17.     } 
  18.  
  19.     public void test(XXXManager ab, XXXSubInterface xxxSubInterface) { 
  20.         ab.setXXX(xxxSubInterface); 
  21.     } 
  22.  
  23. public interface XXX {} 
  24.  
  25. public interface XXXSubInterface extends XXX {} 
  26.  
  27. public interface XXXManager { 
  28.     void setXXX(XXX xxx); 

添加JVM -varbose參數進行執行,輸出是:

  1. [Loaded Main from file:/Users/mazhibin/project/java/loadclasstest/target/classes/] 
  2. Main static block 
  3. [Loaded Helper from file:/Users/mazhibin/project/java/loadclasstest/target/classes/] 
  4. [Loaded XXX from file:/Users/mazhibin/project/java/loadclasstest/target/classes/] 
  5. Helper static block 
  6. Helper#staticMethod 

main方法執行Helper.staticMethod(),而staticMethod方法里面只有打印語句,所以理論上應該只要加載Helper就夠了,為了什么會加載到XXX類,好,即使接受可以加載類的情況,為什么是XXX,而不是直接使用到的XXXManager或者XXXSubInterface。你提的問題大概是這個場景。

在說探索過程之前先說下最終結論:在驗證Helper類時,校驗到setXXX方法,會驗證XXXSubInterface類型是否可以賦值到XXX類型,這個時候就會去加載XXX類,然后因為XXX是一個接口,代碼中認為接口和Object類是一樣的,什么類型都可以賦值給接口類型,所以就直接校驗成功,就沒有去加載XXXSubInterface類了。

然后在介紹一下類加載的過程。首先要清楚一點,“類加載”和“加載”是兩個概念,“加載”是“類加載”(Class Loading)的一個步驟。類加載包含加載、鏈接、初始化這三個步驟,其中鏈接又分為驗證、準備、解析這三個子步驟。加載是根據特定名稱查找類或接口類型的二進制表示(Binary Representation),并由此二進制表示創建類或接口的過程。鏈接是為了讓類或接口可以被 Java 虛擬機執行,而將類或接口并入虛擬機運行時狀態的過程。類或接口的初始化是指執行類或接口的初始化方法

 

JVM源碼分析-類加載場景實例分析

 

類加載復雜就復雜在這些步驟執行的時機,并且其中的子步驟還不一定按順序執行,加載、驗證、準備、初始化和卸載這5個階段的順序是固定的,需要按這個順序開始(允許交叉),而解析則不一定,有可能在初始化之后才進行。

那什么時候會開始加載步驟?Java虛擬機規范沒有強制要求,但是對于初始化階段,則明確規定了5種情況需要對類進行初始化,分別是:

  1. 在執行下列需要引用類或接口的Java虛擬機指令時:new,getstatic,putstatic或invokestatic。這些指令通過字段或方法引用來直接或間接地引用其它類。執行上面所述的new指令,在類或接口沒有被初始化過時就初始化它。執行上面的getstatic,putstatic或invokestatic指令時,那些解析好的字段或方法中的類或接口如果還沒有被初始化那就初始化它。
  2. 在初次調用java.lang.invoke.MethodHandle實例時,它的執行結果為通過Java虛擬機解析出類型是2(REF_getStatic)、4(REF_putStatic)或者6(REF_invokeStatic)的方法句柄(§5.4.3.5)。
  3. 在調用JDK核心類庫中的反射方法時,例如,Class類或java.lang.reflect包。
  4. 在對于類的某個子類的初始化時。
  5. 在它被選定為Java虛擬機啟動時的初始類(§5.2)時。

結合上面說的,加載、驗證、準備、初始化和卸載這5個階段的順序是固定的,需要按這個順序開始(允許交叉),我們確定了初始化的時機,那么在初始化時或者之前,就要開始加載了。同時還有一點,也就是這個問題涉及到的場景,一個類在驗證這個步驟時,會驗證A類的字節碼,其中可能會涉及到所以來的其他類,根據驗證的具體需求,可能需要加載其他類。而這個問題具體的校驗過程就是一個方法調用,涉及到類型轉換賦值(傳入子接口類型,需要轉為父接口類型),這種情況下需要加載類型來判斷是否可以進行賦值,按理是需要加載賦值左右兩邊的類型的,但是因為左邊類型是接口,被認為都可以賦值,所以沒有加載右邊類型。

總結來說可能的加載時機為以下幾點(不一定全面,是我目前已知的):

  1. JVM啟動時會預加載一些核心類,比如Object、String等
  2. 這個類被第一次真正使用到時,比如主類因為要調用其main方法,自然需要被加載
  3. 在A類校驗階段,可能需要加載其代碼中使用到的B類
  4. 在A類進行某個符號引用的解析時,需要加載對應的B類。比如正在執行A類的一個方法,執行到B.func(),那就需要解析B和func符號引用為直接引用,那自然需要加載B類到方法區中

 

接下來說下是如何得到上述結論的,首先類加載的流程是Java虛擬機規范中有寫的,可以看看。而具體為什么只加載了XXX類,則要調試JVM源碼才能知道了。最近因為有看JVM源碼,所以編譯了并可以進行GDB調試,然后添加條件斷點:break SystemDictionary::load_instance_class if strncmp(class_name._body, "XXX", 3) == 0,表示在加載XXX類的時候停下來,接著分析調用堆棧:

  1. / 加載Main類 
  2. [Loaded Main from file:/root/jvm/openjdk/build/linux-amd64-debug/hotspot/outputdir/linux_amd64_compiler2/jvmg/mzb/] 
  3.  
  4. // 執行Main的初始化方法 
  5. Main static block 
  6.  
  7. // 因為要執行Helper.staticMethod()語句,觸發加載Helper流程 
  8. [Loaded Helper from file:/root/jvm/openjdk/build/linux-amd64-debug/hotspot/outputdir/linux_amd64_compiler2/jvmg/mzb/] 
  9.  
  10. // 接著斷點停在了加載XXX接口的函數調用上 
  11. Breakpoint 1, SystemDictionary::load_instance_class (class_name=0x7ffff01a5338, class_loader=..., __the_thread__= 
  12.     0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/classfile/systemDictionary.cpp:1345 
  13. 1345    instanceKlassHandle nh = instanceKlassHandle(); // null Handle 
  14.  
  15. // 查看函數調用棧,分析為什么會需要加載XXX類(要從下往上看) 
  16. (gdb) bt 
  17. #0  SystemDictionary::load_instance_class (class_name=0x7ffff01a5338, class_loader=..., 
  18.     __the_thread__=0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/classfile/systemDictionary.cpp:1345 
  19. #1  0x00007ffff7578062 in SystemDictionary::resolve_instance_class_or_null (name=0x7ffff01a5338, 
  20.     class_loader=..., protection_domain=..., __the_thread__=0x7ffff0028000) 
  21.     at /root/jvm/openjdk/hotspot/src/share/vm/classfile/systemDictionary.cpp:755 
  22. #2  0x00007ffff7576a17 in SystemDictionary::resolve_or_null (class_name=0x7ffff01a5338, class_loader=..., 
  23.     protection_domain=..., __the_thread__=0x7ffff0028000) 
  24.     at /root/jvm/openjdk/hotspot/src/share/vm/classfile/systemDictionary.cpp:203 
  25. #3  0x00007ffff75765ad in SystemDictionary::resolve_or_fail (class_name=0x7ffff01a5338, class_loader=..., 
  26.     protection_domain=..., throw_error=true, __the_thread__=0x7ffff0028000) 
  27.     at /root/jvm/openjdk/hotspot/src/share/vm/classfile/systemDictionary.cpp:145 
  28. // 上面就開始了加載流程了 
  29.  
  30. // 下文分析了這里是在校驗XXXSubInterface類型是否可以賦值到XXX 
  31. // 下文分析了為什么需要加載XXX接口,而不需要加載XXXSubInterface接口 
  32. #4  0x00007ffff75df854 in VerificationType::is_reference_assignable_from (this=0x7ffff7fe5770, from=..., context= 
  33.     0x7ffff7fe60e0, __the_thread__=0x7ffff0028000) 
  34.     at /root/jvm/openjdk/hotspot/src/share/vm/classfile/verificationType.cpp:62 
  35. #5  0x00007ffff753bc37 in VerificationType::is_assignable_from (this=0x7ffff7fe5770, from=..., 
  36.     context=0x7ffff7fe60e0, __the_thread__=0x7ffff0028000) 
  37.     at /root/jvm/openjdk/hotspot/src/share/vm/classfile/verificationType.hpp:289 
  38. #6  0x00007ffff75eba80 in StackMapFrame::pop_stack (this=0x7ffff7fe5e20, type=..., __the_thread__=0x7ffff0028000) 
  39.     at /root/jvm/openjdk/hotspot/src/share/vm/classfile/stackMapFrame.hpp:181 
  40. #7  0x00007ffff75ea155 in ClassVerifier::verify_invoke_instructions (this=0x7ffff7fe60e0, bcs=0x7ffff7fe5dc0, 
  41.     code_length=18, current_frame=0x7ffff7fe5e20, this_uninit=0x7ffff7fe5f1f, return_type=..., cp=..., 
  42.     __the_thread__=0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/classfile/verifier.cpp:2064 
  43.  
  44. // 下文分析了這里是因為驗證Helper.test(LXXXManager;)V這個方法導致的加載XXX接口 
  45. #8  0x00007ffff75e64ea in ClassVerifier::verify_method (this=0x7ffff7fe60e0, m=..., 
  46.     __the_thread__=0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/classfile/verifier.cpp:1237 
  47. #9  0x00007ffff75e0e75 in ClassVerifier::verify_class (this=0x7ffff7fe60e0, __the_thread__=0x7ffff0028000) 
  48.     at /root/jvm/openjdk/hotspot/src/share/vm/classfile/verifier.cpp:312 
  49. #10 0x00007ffff75e04b1 in Verifier::verify (klass=..., mode=Verifier::ThrowException, should_verify_class=true
  50.     __the_thread__=0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/classfile/verifier.cpp:127 
  51. #11 0x00007ffff71f5d8c in instanceKlass::verify_code (this_oop=..., throw_verifyerror=true
  52.     __the_thread__=0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/oops/instanceKlass.cpp:214 
  53. // 上面的方法是驗證的過程,也就是校驗字節碼是否正確,是否合法 
  54.  
  55. #12 0x00007ffff71f6425 in instanceKlass::link_class_impl (this_oop=..., throw_verifyerror=true
  56.     __the_thread__=0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/oops/instanceKlass.cpp:321 
  57. #13 0x00007ffff71f5e73 in instanceKlass::link_class (this=0xfb01ab80, __the_thread__=0x7ffff0028000) 
  58.  
  59. // 在類或接口被初始化之前,它必須被鏈接過,也就是經過驗證、準備階段,且有可能已經被解析完成了。所以上面是鏈接的流程 
  60.     at /root/jvm/openjdk/hotspot/src/share/vm/oops/instanceKlass.cpp:230 
  61. #14 0x00007ffff71f691f in instanceKlass::initialize_impl (this_oop=..., __the_thread__=0x7ffff0028000) 
  62.     at /root/jvm/openjdk/hotspot/src/share/vm/oops/instanceKlass.cpp:397 
  63. #15 0x00007ffff71f5cca in instanceKlass::initialize (this=0xfb01ab80, __the_thread__=0x7ffff0028000) 
  64.     at /root/jvm/openjdk/hotspot/src/share/vm/oops/instanceKlass.cpp:199 
  65. #16 0x00007ffff7383903 in LinkResolver::resolve_static_call (result=..., resolved_klass=..., 
  66.     method_name=0x7ffff01a4908, method_signature=0x7ffff0051f28, current_klass=..., check_access=true
  67.     initialize_class=true, __the_thread__=0x7ffff0028000) 
  68.     at /root/jvm/openjdk/hotspot/src/share/vm/interpreter/linkResolver.cpp:629 
  69.  
  70. // Main類在運行字節碼時,執行到invokestatic指令,對應的語句是Helper.staticMethod() 
  71. // JVM規范中說明,在執行new,getstatic,putstatic或invokestatic這些指令時,需要確保目標類已經進行初始化流程 
  72. // 而初始化流程需要確保目標類已經被加載、驗證、準備,所以上面會走到Helper的加載、驗證、準備的流程 
  73. // 這個堆棧跟蹤到的是驗證的流程 
  74. #17 0x00007ffff738599f in LinkResolver::resolve_invokestatic (result=..., pool=..., index=65537, 
  75.     __the_thread__=0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/interpreter/linkResolver.cpp:1077 
  76. #18 0x00007ffff738575c in LinkResolver::resolve_invoke (result=..., recv=..., pool=..., index=65537, 
  77.     byte=Bytecodes::_invokestatic, __the_thread__=0x7ffff0028000) 
  78.     at /root/jvm/openjdk/hotspot/src/share/vm/interpreter/linkResolver.cpp:1050 
  79. #19 0x00007ffff7239c58 in InterpreterRuntime::resolve_invoke (thread=0x7ffff0028000, 
  80.     bytecode=Bytecodes::_invokestatic) 
  81.     at /root/jvm/openjdk/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp:686 
  82.  
  83. // 我們到第16號棧幀中,可以看出的確是正要執行Helper.staticMethod()方法 
  84. (gdb) f 16 
  85. #16 0x00007ffff7383903 in LinkResolver::resolve_static_call (result=..., resolved_klass=..., 
  86.     method_name=0x7ffff01a4908, method_signature=0x7ffff0051f28, current_klass=..., check_access=true
  87.     initialize_class=true, __the_thread__=0x7ffff0028000) 
  88.     at /root/jvm/openjdk/hotspot/src/share/vm/interpreter/linkResolver.cpp:629 
  89. 629       resolved_klass->initialize(CHECK); 
  90. (gdb) p Klass::cast(current_klass.obj())->external_name() 
  91. $1 = 0x7fffcc002548 "Main" 
  92. (gdb) p *method_name._body@method_name._length 
  93. $5 = "staticMethod" 
  94.  
  95. // 我們到第8號棧幀中,可以看出是因為驗證Helper.test(LXXXManager;)V這個方法導致的加載XXX接口 
  96. (gdb) f 8 
  97. #8  0x00007ffff75e64ea in ClassVerifier::verify_method (this=0x7ffff7fe60e0, m=..., 
  98.     __the_thread__=0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/classfile/verifier.cpp:1237 
  99. 1237                &this_uninit, return_type, cp, CHECK_VERIFY(this)); 
  100. (gdb) p m->name_and_sig_as_C_string() 
  101. $6 = 0x7fffcc002568 "Helper.test(LXXXManager;)V" 
  102.  
  103. // 我們到第4號棧幀中,可以看出是在校驗XXXSubInterface類型是否可以賦值到XXX 
  104. (gdb) f 4 
  105. #4  0x00007ffff75df854 in VerificationType::is_reference_assignable_from (this=0x7ffff7fe5770, from=..., 
  106.     context=0x7ffff7fe60e0, __the_thread__=0x7ffff0028000) 
  107.     at /root/jvm/openjdk/hotspot/src/share/vm/classfile/verificationType.cpp:62 
  108. 62          Handle(THREAD, klass->protection_domain()), true, CHECK_false); 
  109. (gdb) p *from.name()._body@from.name()._length 
  110. $10 = "XXXSubInterface" 
  111. (gdb) p *name()._body@name()._length 
  112. $11 = "XXX" 

上面分析出了加載是因為驗證的流程,具體觸發加載的驗證代碼如下,是驗證賦值操作是否可以成功的:

  1. // hotspot/src/share/vm/classfile/verificationType.cpp 
  2. bool VerificationType::is_reference_assignable_from( 
  3.     const VerificationType& from, ClassVerifier* context, TRAPS) const { 
  4.   instanceKlassHandle klass = context->current_class(); 
  5.   if (from.is_null()) { 
  6.     // null is assignable to any reference 
  7.     return true
  8.   } else if (is_null()) { 
  9.     return false
  10.   } else if (name() == from.name()) { 
  11.     return true
  12.   } else if (is_object()) { 
  13.     // 如果賦值語句左邊類型是對象,判斷是否是Object,如果是那都可以賦值成功,返回true 
  14.     // We need check the class hierarchy to check assignability 
  15.     if (name() == vmSymbols::java_lang_Object()) { 
  16.       // any object or array is assignable to java.lang.Object 
  17.       return true
  18.     } 
  19.  
  20.     // 否則需要把左邊類型加載進來 <=========================== 加載行為發生在這里 
  21.     klassOop obj = SystemDictionary::resolve_or_fail( 
  22.         name(), Handle(THREAD, klass->class_loader()), 
  23.         Handle(THREAD, klass->protection_domain()), true, CHECK_false); 
  24.     KlassHandle this_class(THREAD, obj); 
  25.  
  26.     // 如果左邊類型是接口 
  27.     if (this_class->is_interface()) { 
  28.       // 這里注釋說明了,認為接口和Object一樣,都可以賦值成功所以返回true 
  29.       // We treat interfaces as java.lang.Object, including 
  30.       // java.lang.Cloneable and java.io.Serializable 
  31.       return true
  32.     } else if (from.is_object()) { 
  33.       // 否則要把賦值賦予右邊的類型也加載進來 
  34.       klassOop from_class = SystemDictionary::resolve_or_fail( 
  35.           from.name(), Handle(THREAD, klass->class_loader()), 
  36.           Handle(THREAD, klass->protection_domain()), true, CHECK_false); 
  37.       return instanceKlass::cast(from_class)->is_subclass_of(this_class()); 
  38.     } 
  39.   } else if (is_array() && from.is_array()) { 
  40.     VerificationType comp_this = get_component(context, CHECK_false); 
  41.     VerificationType comp_from = from.get_component(context, CHECK_false); 
  42.     if (!comp_this.is_bogus() && !comp_from.is_bogus()) { 
  43.       return comp_this.is_assignable_from(comp_from, context, CHECK_false); 
  44.     } 
  45.   } 
  46.   return false

這樣就分析完了,嘗試把XXX和XXXSubInterface改成class,可以發現兩個都會被加載,符合上面這個代碼的邏輯。

接著順便分析一下Helper類加載的堆棧:

  1. // 加載Main類 
  2. [Loaded Main from file:/root/jvm/openjdk/build/linux-amd64-debug/hotspot/outputdir/linux_amd64_compiler2/jvmg/mzb/] 
  3.  
  4. // 執行Main初始化方法 
  5. Main static block 
  6.  
  7. // 斷點停在加載Helper類的邏輯上 
  8. Breakpoint 2, SystemDictionary::load_instance_class (class_name=0x7ffff01a60d8, class_loader=..., __the_thread__= 
  9.     0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/classfile/systemDictionary.cpp:1345 
  10. 1345      instanceKlassHandle nh = instanceKlassHandle(); // null Handle 
  11. (gdb) bt 
  12. #0  SystemDictionary::load_instance_class (class_name=0x7ffff01a60d8, class_loader=..., 
  13.     __the_thread__=0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/classfile/systemDictionary.cpp:1345 
  14. #1  0x00007ffff7578062 in SystemDictionary::resolve_instance_class_or_null (name=0x7ffff01a60d8, 
  15.     class_loader=..., protection_domain=..., __the_thread__=0x7ffff0028000) 
  16.     at /root/jvm/openjdk/hotspot/src/share/vm/classfile/systemDictionary.cpp:755 
  17. #2  0x00007ffff7576a17 in SystemDictionary::resolve_or_null (class_name=0x7ffff01a60d8, class_loader=..., 
  18.     protection_domain=..., __the_thread__=0x7ffff0028000) 
  19.     at /root/jvm/openjdk/hotspot/src/share/vm/classfile/systemDictionary.cpp:203 
  20. #3  0x00007ffff75765ad in SystemDictionary::resolve_or_fail (class_name=0x7ffff01a60d8, class_loader=..., 
  21.     protection_domain=..., throw_error=true, __the_thread__=0x7ffff0028000) 
  22.     at /root/jvm/openjdk/hotspot/src/share/vm/classfile/systemDictionary.cpp:145 
  23. #4  0x00007ffff70c1915 in constantPoolOopDesc::klass_at_impl (this_oop=..., which=18, 
  24.     __the_thread__=0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/oops/constantPoolOop.cpp:102 
  25. #5  0x00007ffff6fa1f69 in constantPoolOopDesc::klass_at (this=0xfb019e90, which=18, 
  26.     __the_thread__=0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/oops/constantPoolOop.hpp:366 
  27. #6  0x00007ffff70c2c84 in constantPoolOopDesc::klass_ref_at (this=0xfb019e90, which=65537, 
  28.     __the_thread__=0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/oops/constantPoolOop.cpp:382 
  29. #7  0x00007ffff73817c0 in LinkResolver::resolve_klass (result=..., pool=..., index=65537, 
  30.     __the_thread__=0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/interpreter/linkResolver.cpp:161 
  31. #8  0x00007ffff7385871 in LinkResolver::resolve_pool (resolved_klass=..., method_name=@0x7ffff7fe6638: 0x0, 
  32.     method_signature=@0x7ffff7fe6630: 0x0, current_klass=..., pool=..., index=65537, 
  33.     __the_thread__=0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/interpreter/linkResolver.cpp:1062 
  34.  
  35. // Main類在運行字節碼時,執行到invokestatic指令,對應的語句是Helper.staticMethod() 
  36. // JVM規范中說明,指令anewarray、checkcast、getfield、getstatic、instanceof、nvokedynamic、invokeinterface、invokespecial、invokestatic、invokevirtual、ldc、ldc_w、multianewarray、new、putfield和putstatic將符號引用指向運行時常量池,執行上述任何一條指令都需要對它的符號引用的進行解析。 
  37. // 所以這里需要將Main中的運行時常量池中的Helper和staticMethod進行符號解析 
  38. // 符號解析是把符號引用替換為真實引用,自然需要加載Helper類,才能進行替換,所以上面就觸發了Helper的加載流程 
  39. #9  0x00007ffff738595b in LinkResolver::resolve_invokestatic (result=..., pool=..., index=65537, 
  40.     __the_thread__=0x7ffff0028000) at /root/jvm/openjdk/hotspot/src/share/vm/interpreter/linkResolver.cpp:1076 
  41. #10 0x00007ffff738575c in LinkResolver::resolve_invoke (result=..., recv=..., pool=..., index=65537, 
  42.     byte=Bytecodes::_invokestatic, __the_thread__=0x7ffff0028000) 
  43.     at /root/jvm/openjdk/hotspot/src/share/vm/interpreter/linkResolver.cpp:1050 
  44. #11 0x00007ffff7239c58 in InterpreterRuntime::resolve_invoke (thread=0x7ffff0028000, 
  45. ---Type <return> to continue, or q <return> to quit--- 
  46.     bytecode=Bytecodes::_invokestatic) 
  47.     at /root/jvm/openjdk/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp:686 

  1. // hotspot/src/share/vm/interpreter/linkResolver.cpp 
  2. void LinkResolver::resolve_invokestatic(CallInfo& result, constantPoolHandle pool, int index, TRAPS) { 
  3.   KlassHandle  resolved_klass; 
  4.   Symbol* method_name = NULL
  5.   Symbol* method_signature = NULL
  6.   KlassHandle  current_klass; 
  7.   // 解析常量池中的符號引用,會觸發加載被調用類的流程 <================== 
  8.   resolve_pool(resolved_klass, method_name,  method_signature, current_klass, pool, indexCHECK); 
  9.   // 解析從方法簽名解析出方法oop,會觸發類的初始化流程 <================== 
  10.   resolve_static_call(result, resolved_klass, method_name, method_signature, current_klass, truetrueCHECK); 

總結

總結來說可能的加載時機為以下幾點(不一定全面,是我目前已知的):

  1. JVM啟動時會預加載一些核心類,比如Object、String等
  2. 這個類被第一次真正使用到時,比如主類因為要調用其main方法,自然需要被加載
  3. 在A類校驗階段,可能需要加載其代碼中使用到的B類
  4. 在A類進行某個符號引用的解析時,需要加載對應的B類。比如正在執行A類的一個方法,執行到B.func(),那就需要解析B和func符號引用為直接引用,那自然需要加載B類到方法區中

對應A類調用B類的情況,JVM規范中說明,指令anewarray、checkcast、getfield、getstatic、instanceof、nvokedynamic、invokeinterface、invokespecial、invokestatic、invokevirtual、ldc、ldc_w、multianewarray、new、putfield和putstatic將符號引用指向運行時常量池,執行上述任何一條指令都需要對它的符號引用的進行解析,所以需要解析A類中對B類的符號引用,而解析是把符號引用替換為真實引用,所以需要把B類加載到方法區中,這就觸發了加載流程。

而B類的鏈接流程,則是因為JVM規范中說明,在執行new,getstatic,putstatic或invokestatic這些指令時,需要確保目標類已經進行初始化流程,而初始化流程需要確保目標類已經被加載、驗證、準備,而加載之前執行過了,所以需要進入驗證和準備的流程。而鏈接中的解析過程不會執行,B類的解析會在執行B類中相關代碼時再進行。

 

上面說的兩個過程都是在執行字節碼時觸發的,比如invokestaic。而B類在驗證的過程中,可能又會需要加載其代碼中使用到的C類。

責任編輯:姜華 來源: 今日頭條
相關推薦

2023-10-31 16:00:51

類加載機制Java

2015-08-10 15:12:27

Java實例源碼分析

2012-11-06 10:19:18

Java自定義加載Java類

2020-07-28 08:54:39

內核通信Netlink

2017-01-12 14:52:03

JVMFinalRefere源碼

2017-02-27 11:48:58

JVM源碼分析Java

2021-03-11 08:10:48

JVM對象的創建School

2014-04-29 13:16:42

OpenGLAndroid庫加載過程

2012-01-11 11:40:57

JavaJVM

2011-05-16 15:49:58

JAVA

2009-05-18 13:07:44

類隱藏Java關鍵字

2017-01-11 14:02:32

JVM源碼內存

2017-09-26 16:32:03

JavaGC分析

2020-05-26 18:50:46

JVMAttachJava

2009-07-08 13:22:30

JDK源碼分析Set

2017-03-08 10:30:43

JVMJava加載機制

2020-07-21 14:19:18

JVM編程語言

2009-06-05 10:43:29

struts2 checheckbox實例

2011-03-15 10:09:11

2017-09-20 08:07:32

java加載機制
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产一级片av | 女人av| 亚洲高清在线观看 | 成人天堂噜噜噜 | 日韩一二三 | 日本久久一区 | 国产精品99久久久久久动医院 | 国产一区 在线视频 | 久久国产一区二区三区 | 成人av电影网 | 999精品视频| 中文字幕精品一区二区三区精品 | 久久精品视频播放 | 欧美伦理一区 | 久草电影网 | 午夜影院网站 | 国产精品一二三区 | 一区二区三区在线电影 | 亚洲欧美综合精品久久成人 | 国产精品一区二区三区在线 | 国产精品视频播放 | 欧美一区二区三区在线观看视频 | 亚洲天堂成人在线视频 | 一久久久| 成人精品| 久婷婷 | 亚洲国产精品久久 | 国产精品久久九九 | 亚洲免费人成在线视频观看 | 99九色 | 欧美一区二区久久 | 精品无码久久久久久国产 | 日韩视频在线观看一区二区 | 久久69精品久久久久久久电影好 | 成人网在线观看 | 在线欧美一区二区 | 国产色视频网站 | 最新中文字幕一区 | 精品一区二区三区在线观看国产 | 韩日一区二区 | 亚洲毛片在线观看 |