淺談JVM-圖解類加載機制

1、目錄

2、類加載機制流程

一、什麼是類加載機制?

  JVM把class文件加載到內存裏面,並對數據進行校驗、準備、解析和初始化,最終可以被造成被JVM能夠直接使用的Java類型的過程。java

二、類加載流程圖

三、加載

  1. 將class文件加載在內存中。
  2. 將靜態數據結構(數據存在於class文件的結構)轉化成方法區中運行時的數據結構(數據存在於JVM時的數據結構)。
  3. 在堆中生成一個表明這個類的java.lang.Class對象,做爲數據訪問的入口。

四、連接

 連接就是將Java類的二進制代碼合併到java的運行狀態中的過程。數組

  • 驗證:確保加載的類符合JVM規範與安全。
  • 準備:爲static變量在方法區中分配空間,設置變量的初始值。例如static int a=3,在此階段會a被初始化爲0,其餘數據類型參考成員變量聲明。
  • 解析:虛擬機將常量池的符號引用轉變成直接引用。例如"aaa"爲常量池的一個值,直接把"aaa"替換成存在於內存中的地址。
    • 符號引用:符號引用以一組符號來描述所引用的目標,符號能夠是任何形式的字面量,只要使用時能無歧義地定位到目標便可。符號引用與虛擬機實現的內存佈局無關,引用 的目標並不必定已經加載到內存中。
    • 直接引用:直接引用能夠是直接指向目標的指針、相對偏移量或是一個能間接定位到目標的句柄。直接引用是與虛擬機實現的內存佈局相關的,若是有了直接引用,那麼引用的目標一定已經在內存中存在。

五、初始化

  初始化階段是執行類構造器<clinit>()方法。在類構造器方法中,它將由編譯器自動收集類中的全部類變量的賦值動做(準備階段的a正是被賦值a)和靜態變量與靜態語句塊static{}合併,初始化時機後續再聊。安全

六、使用

  正常使用。數據結構

七、卸載

  GC把無用對象從內存中卸載。佈局

3、類加載與初始化時機

一、類加載時機測試

  當應用程序啓動的時候,全部的類會被一次性加載嗎?估計你早已知道答案,固然不能,由於若是一次性加載,內存資源有限,可能會影響應用程序的正常運行。那類何時被加載呢?例如,A a=new A(),一個類真正被加載的時機是在建立對象的時候,纔會去執行以上過程,加載類。當咱們測試的時候,最早加載擁有main方法的主線程所在類。spa

二、類初始化時機線程

 主動引用(發生類初始化過程)指針

  1. new一個對象。
  2. 調用類的靜態成員(除了final常量)和靜態方法。
  3. 經過反射對類進行調用。
  4. 虛擬機啓動,main方法所在類被提早初始化。
  5. 初始化一個類,若是其父類沒有初始化,則先初始化父類。

 被動引用(不會發生類的初始化)code

  1. 當訪問一個靜態變量時,只有真正聲明這個變量的類纔會初始化。(子類調用父類的靜態變量,只有父類初始化,子類不初始化)。
  2. 經過數組定義類引用,不會觸發此類的初始化。
  3. final變量不會觸發此類的初始化,由於在編譯階段就存儲在常量池中。

4、圖解分析類加載

 1 public class ClassLoaderProduce {
 2     static int d=3;
 3     static{
 4         System.out.println("我是ClassLoaderProduce類");
 5     }
 6     public static void main(String [] args){
 7         int b=0;
 8         String c="hello";
 9         SimpleClass simpleClass=new SimpleClass();
10         simpleClass.run();
11     }
12 }
13 
14 class SimpleClass{
15     static int  a=3;
16     static{
17         a=100;
18         System.out.println(a);
19     }
20 
21     public SimpleClass(){
22         System.out.println("對類進行加載!");
23     }
24 
25     public void run(){
26         System.out.println("我要跑跑跑!");
27     }
28 }

步驟一:裝載ClassLoaderProduce類,在方法區生成動態數據結構(靜態變量、靜態方法、常量池、類代碼),而且在堆中生成java.lang.Class對象;而後進行連接

步驟二:初始化:把static{}與靜態變量合併存放在類構造器當中,對靜態變量賦值。 1-5行執行完畢。

步驟三:執行main方法,首先在棧裏面生成一個main方法的棧禎,定義變量b、c,注意此處的變量b、c存儲的常量池存儲的變量的地址,如圖所示。

步驟四:建立SimpleClass對象;跟上面步驟相似:加載-連接-初始化。而後,調用run()方法的時候,它會經過classLoader局部變量的地址尋找到類的class對象而且調用run()方法

相關文章
相關標籤/搜索