精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

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-02-27 11:48:58

JVM源碼分析Java

2017-01-12 14:52:03

JVMFinalRefere源碼

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源碼內存

2020-05-26 18:50:46

JVMAttachJava

2017-09-26 16:32:03

JavaGC分析

2009-07-08 13:22:30

JDK源碼分析Set

2017-03-08 10:30:43

JVMJava加載機制

2017-09-20 08:07:32

java加載機制

2020-07-21 14:19:18

JVM編程語言

2011-03-15 10:09:11

2009-06-05 10:43:29

struts2 checheckbox實例
點贊
收藏

51CTO技術棧公眾號

一区二区精品国产| 国产精品网红直播| 波多野结衣有码| 毛片无码国产| 中文字幕在线播放av| 久久电影在线| 欧美吻胸吃奶大尺度电影 | 亚洲欧洲精品天堂一级 | 亚洲色图在线播放| 精品视频在线观看| 在线免费观看一级片| 亚洲高清二区| 中文字幕亚洲欧美一区二区三区| 国产精品19p| 日韩三区免费| 亚洲成人一区二区在线观看| 欧美一区二区三区电影在线观看| 国产免费av电影| 新67194成人永久网站| 久久五月天综合| 魔女鞋交玉足榨精调教| 久久国产精品免费一区二区三区| 欧美性猛交xxxx免费看| 成人免费看片视频在线观看| 免费在线超碰| 丁香网亚洲国际| 成人黄色av网| 久久久精品毛片| 亚洲美女啪啪| 欧美激情久久久| 日韩福利小视频| 国产精品欧美日韩一区| 亚洲第一中文字幕| 精品人妻一区二区三| 日本精品另类| 欧美性69xxxx肥| 九九热只有这里有精品| 国产1区在线| 国产日本欧美一区二区| 精品一区2区三区| 免费av网站在线播放| 国产乱人伦精品一区二区在线观看| 国产精品成人va在线观看| 激情五月色婷婷| 精品av久久久久电影| 欧美成人性色生活仑片| 手机在线中文字幕| 欧美亚洲激情| 在线视频日韩精品| 熟女少妇内射日韩亚洲| 啪啪亚洲精品| 亚洲香蕉成人av网站在线观看| www.超碰97| 色先锋久久影院av| 亚洲精品视频久久| 色呦呦一区二区| 伊人久久大香线蕉| 亚洲美女av在线播放| 插吧插吧综合网| 香蕉精品久久| 国产一区二区三区日韩欧美| 我想看黄色大片| 日韩中字在线| 久热精品在线视频| 欧美成人精品欧美一| 韩国在线视频一区| 97在线观看视频| 美日韩一二三区| 久久综合九色| 国产在线精品自拍| 精品国产亚洲av麻豆| 国产suv精品一区二区三区| 国产98在线|日韩| 日本黄色大片视频| 久久久蜜臀国产一区二区| 亚洲国产精品123| 成人在线免费看片| 亚洲一区二区三区小说| av免费播放网址| 成人福利片在线| 91精品欧美综合在线观看最新| 亚洲911精品成人18网站| 欧美挤奶吃奶水xxxxx| 亚洲午夜激情免费视频| 午夜爽爽爽男女免费观看| 亚洲小说欧美另类婷婷| 日韩av片电影专区| 国产精品久久久久久在线| 国产91丝袜在线18| 欧美中文娱乐网| 最新av在线播放| 欧美视频在线观看免费| 男女视频在线看| av综合网址| 中文综合在线观看| 日本三级视频在线| 美女久久久精品| 成人av网站观看| 成人欧美亚洲| 亚洲成人在线观看视频| 国产一级做a爰片久久| 日韩一区二区三区在线看| 亚洲欧美国产一区二区三区 | 一区二区在线电影| 黑人糟蹋人妻hd中文字幕| 欧美一区=区三区| 亚洲国内高清视频| 久草视频手机在线| 亚洲欧美清纯在线制服| 亚洲a区在线视频| 国产在线电影| 午夜精品影院在线观看| 手机免费av片| 国产91久久精品一区二区| 欧美剧在线观看| 在线不卡免费视频| 久久夜色精品国产噜噜av| 91大学生片黄在线观看| 91国拍精品国产粉嫩亚洲一区 | 国产探花在线免费观看| 一区二区日韩免费看| 成人亲热视频网站| 国产大学生校花援交在线播放| 一区二区久久久久久| 成人在线观看a| 久久97精品| 欧美极品在线视频| 精品人妻一区二区三区换脸明星| 国产欧美日韩视频一区二区| 婷婷五月综合缴情在线视频| www999久久| 中文字幕日韩在线视频| 日日摸天天添天天添破| 成人a免费在线看| 337p亚洲精品色噜噜狠狠p| 日本黄色成人| 色悠悠国产精品| 一级片在线免费播放| 久久久久久99精品| 亚洲美免无码中文字幕在线| eeuss鲁片一区二区三区| 欧美成人免费在线视频| 国产欧美综合视频| 日韩毛片一二三区| 欧美性猛交xxxx乱大交91| 久久一区二区三区电影| 国产精品自拍偷拍视频| 大片免费播放在线视频| 色婷婷综合中文久久一本| 性欧美13一14内谢| 美女尤物久久精品| 欧美xxxx黑人又粗又长精品| xxxxxx欧美| 亚洲人a成www在线影院| 波多野结衣二区三区| 国产亚洲综合色| 99热成人精品热久久66| 欧美热在线视频精品999| 日本精品视频在线| 99中文字幕一区| 欧美日韩精品是欧美日韩精品| 国产极品视频在线观看| 久久99精品视频| 日韩不卡视频一区二区| 中文字幕一区图| 国内成人精品一区| 欧美色18zzzzxxxxx| 日本韩国欧美国产| 一本在线免费视频| 国产一区二区不卡| 国产 日韩 亚洲 欧美| 在线观看欧美理论a影院| 国产精品第二页| 成人直播在线| 亚洲精品久久久久中文字幕二区| 五月婷婷激情视频| 中文字幕中文字幕在线一区 | 久久综合伊人77777| www男人的天堂| 欧美日韩亚洲一区二| 日本xxxxxxxxx18| 国产自产2019最新不卡| 男的插女的下面视频| 欧洲杯半决赛直播| 91国产在线播放| 奇米777日韩| 久久精品欧美视频| 亚洲av成人无码久久精品老人| 欧美吻胸吃奶大尺度电影| 黄色一级免费视频| 国产午夜精品在线观看| 国产精品久久久久久久99| 国产欧美日韩一级| 综合视频免费看| 香蕉久久精品日日躁夜夜躁| 91精品久久久久久久久| 成入视频在线观看| 最近更新的2019中文字幕 | 精品一区二区三区电影| 亚洲性在线观看| 精品久久久一区二区| 欧美爱爱免费视频| 国产视频一区二区三区在线观看| 无套内谢丰满少妇中文字幕| 天堂久久一区二区三区| 欧美日韩激情四射| 日韩系列欧美系列| 久久久久久久久久久久久久久久av| 亚洲伊人精品酒店| 国产不卡视频在线| 久草在线资源站资源站| 日韩在线观看成人| 久久电影视频| 亚洲精品一区二区三区影院 | 日韩黄色精品视频| ●精品国产综合乱码久久久久| 亚洲人人夜夜澡人人爽| 高清国产一区二区三区| 福利视频999| 日日骚欧美日韩| 欧美极品欧美精品欧美| 欧美日韩综合| 看一级黄色录像| 日韩视频在线观看| 日韩av图片| 亚洲调教一区| 久热这里只精品99re8久 | 小视频免费在线观看| 欧美丰满片xxx777| 成人在线免费看片| 精品国偷自产在线视频| av中文字幕在线| 亚洲欧美在线x视频| 午夜成人免费影院| 精品电影一区二区| 成人免费视频国产免费麻豆| 欧美一区日韩一区| 99国产精品久久久久久久成人 | 亚洲一区二区精品视频| 破处女黄色一级片| 亚洲乱码精品一二三四区日韩在线| 91社区视频在线观看| 欧美激情一区二区三区不卡| 亚洲自拍偷拍图| 国产午夜亚洲精品不卡| 亚洲精品乱码久久久久久久久久久久 | 亚洲欧美色视频| 日韩精品极品视频免费观看| 亚洲aaa在线观看| 日韩av在线直播| 亚洲色图21p| 日韩精品一二三四区| 你懂的视频在线观看| 亚洲精品网站在线播放gif| 亚洲av成人无码久久精品老人| 国产视频亚洲视频| 免费一级毛片在线观看| 亚洲午夜av电影| 人人干在线视频| 欧美另类高清videos| 欧洲黄色一区| 欧美性做爰毛片| 韩日精品一区二区| 国产精品老牛影院在线观看| 日本久久久久| 成人久久18免费网站漫画| 国产乱人伦精品一区| 精品久久蜜桃| 国产影视精品一区二区三区| 亚洲欧美久久234| 亚洲中无吗在线| 日韩网站在线免费观看| 久久精品成人| 国模私拍视频在线观看| 国产黄人亚洲片| 黄色正能量网站| 国产精品不卡一区| 国产精品50页| 欧美亚日韩国产aⅴ精品中极品| 亚洲一级黄色大片| 精品少妇一区二区| 久久经典视频| 欧美日韩国产999| 在线观看v片| 成人xvideos免费视频| 韩国女主播一区二区三区| 日本三级中国三级99人妇网站| 亚洲电影在线一区二区三区| 日韩五码在线观看| 久久国产精品第一页| 亚洲成年人在线观看| 国产日产欧美一区| 欧美爱爱小视频| 欧美撒尿777hd撒尿| 色噜噜一区二区三区| 中文字幕av一区二区| av蜜臀在线| 成人网在线免费观看| 天海翼亚洲一区二区三区| 最新黄色av网站| 美女日韩在线中文字幕| 久久久久亚洲av无码网站| 国产日韩三级在线| 国产网站在线看| 欧美剧情片在线观看| 欧美日本韩国一区二区| 欧美黄色片免费观看| 日韩欧乱色一区二区三区在线 | 午夜在线电影亚洲一区| 亚洲一区二区三区网站| 日韩精品在线免费播放| 一色桃子av在线| 国产精品一区二区久久久| 亚洲小说图片| 少妇人妻在线视频| 国产一级精品在线| 奇米网一区二区| 一本久久综合亚洲鲁鲁五月天| 风流老熟女一区二区三区| 精品国产欧美一区二区五十路| 欧美一级大黄| 久久99精品久久久久久久久久 | 四虎影视精品| 欧美不卡在线播放| 国产精品99久久久久久久vr| 99热这里只有精品4| 91福利在线看| 天天色天天操天天射| 欧美激情性做爰免费视频| 国产乱码精品一区二区三区亚洲人| 亚洲成人第一| 日本欧美一区二区三区乱码| 日韩一级av毛片| 一本色道久久综合狠狠躁的推荐 | 成品人视频ww入口| 国产成a人亚洲| 国产十六处破外女视频| 日韩一卡二卡三卡四卡| 在线免费av导航| 亚洲精品日韩av| 中文字幕人成人乱码| 日本网站在线看| 亚洲精品伦理在线| 精品欧美一区二区精品少妇| 欧美精品手机在线| 秋霞影院一区| 美女黄色免费看| 成年人网站91| 亚洲男人的天堂在线视频| 亚洲男人天堂2024| 欧美大胆性生话| 亚洲 国产 日韩 综合一区| 日本va欧美va精品| 糖心vlog免费在线观看| 欧美一区二区福利视频| 日韩av官网| 韩国精品一区二区三区六区色诱| 999亚洲国产精| 精品无码一区二区三区| 在线观看亚洲a| 日本成人网址| 91九色在线观看| 99精品视频免费| 97人妻精品一区二区免费| 欧美系列在线观看| 欧美jizz18hd性欧美| 99中文字幕| 欧美综合二区| 毛片久久久久久| 欧美一二三区在线| 9999热视频在线观看| 清纯唯美一区二区三区| 久久99蜜桃精品| 久久久久99精品成人片毛片| 日韩精品视频观看| 国产一区影院| 国产一区二区三区小说| 久久这里只有精品6| 一区二区 亚洲| 久久久久久亚洲| 精品国产乱码久久久久久蜜坠欲下| 57pao国产成永久免费视频| 尤物在线观看一区| 你懂得在线网址| 91中文字幕一区| 亚洲专区在线| 麻豆天美蜜桃91| 日韩精品在线视频观看| 综合欧美精品| 成人在线免费观看av| 亚洲视频免费在线观看| 免费黄色在线视频网站| 亚洲综合日韩在线| 日韩精品免费专区| 久久久久久久久久久久国产| 亚洲视频一区二区| 99精品国产高清一区二区麻豆| 天天爱天天操天天干| 亚洲sss视频在线视频| 日本美女高清在线观看免费|