走馬觀花了解jvm spec

目的

  • 深入理解java,學習瞭解,本文記錄一些個人認爲有用的一些知識點

1.2 Java虛擬機

  • Java虛擬機與Java語言並沒有必然的聯繫,它只與特定的二進制文件格式——Class文件格式所關聯,Class文件中包含了Java虛擬機指令集(或者稱爲字節碼、Bytecodes)和符號表,還有一些其他輔助信息。

2 Java虛擬機結構

  • 如果只是要去“正確地”實現一臺Java虛擬機,其實並不如大多數人所想的那樣高深和困難——只需要正確讀取Class文件之中每一條字節碼指令,並且能正確執行這些指令所蘊含的操作即可。

2.2 數據類型

  • 與Java程序語言中的數據類型相似,Java虛擬機可以操作的數據類型可分爲兩類:原始類型(Primitive Types,也經常翻譯爲原生類型或者基本類型)和引用類型(Reference Types)。虛擬機中使用reference類型①來表示對某個對象的引用,reference類型的值讀者可以想象成類似於一個指向對象的指針。

2.3.4 boolean類型

  • 雖然Java虛擬機定義了boolean這種數據類型,但是隻對它提供了非常有限的支持。在Java虛擬機中沒有任何供boolean值專用的字節碼指令,在Java語言之中涉及到boolean類型值的運算,在編譯之後都使用Java虛擬機中的int數據類型來代替。

2.5 運行時數據區

  • 見文後博客解析

2.11.8 方法調用和返回指令

  • 以下四條指令用於方法調用:
    “`
    invokevirtual指令用於調用對象的實例方法,根據對象的實際類型進行分派(虛方法分派),這也是Java語言中最常見的方法分派方式。
    invokeinterface指令用於調用接口方法,它會在運行時搜索一個實現了這個接口方法的對象,找出適合的方法進行調用。
    invokespecial指令用於調用一些需要特殊處理的實例方法,包括實例初始化方法(§2.9)、私有方法和父類方法。
    invokestatic指令用於調用類方法(static方法)。

而方法返回指令則是根據返回值的類型區分的,
包括有ireturn(當返回值是boolean、byte、char、short和int類型時使用)、
lreturn、freturn、dreturn和areturn,
另外還有一條return指令供聲明爲void的方法、實例初始化方法、類和接口的類初始化方法使用。
“`

3.12 拋出異常和處理異常

  • 如果在try語句塊執行過程中沒有異常拋出,程序那麼就猶如沒有使用try結構一樣。(無任何性能損失)

3.14 同步

  • Java虛擬機中的同步(Synchronization)基於進入和退出管程(Monitor)對象實現。無論是顯式同步(有明確的monitorenter和monitorexit指令)還是隱式同步(依賴方法調用和返回指令實現的)都是如此。
  • 在Java語言中,同步用的最多的地方可能是被synchronized修飾的同步方法。同步方法並不是由monitorenter和monitorexit指令來實現同步的,而是由方法調用指令讀取運行時常量池中方法的ACC_SYNCHRONIZED標誌來隱式實現的。

4.1 ClassFile結構

  • 每一個Class文件對應於一個如下所示的ClassFile結構體

    ClassFile { 
    u4 magic; 
    u2 minor_version; 
    u2 major_version; 
    u2 constant_pool_count; 
    cp_info constant_pool[constant_pool_count-1]; 
    u2 access_flags; 
    u2 this_class; 
    u2 super_class; 
    u2 interfaces_count;
    u2 interfaces[interfaces_count]; 
    u2 fields_count; 
    field_info fields[fields_count]; 
    u2 methods_count; 
    method_info methods[methods_count]; 
    u2 attributes_count; 
    attribute_info attributes[attributes_count]; 
    }

4.3.3 方法描述符

  • 無論mymethod()是靜態方法還是實例方法,它的方法描述符都是相同的。儘管實例方法除了傳遞自身定義的參數,還需要額外傳遞參數this,但是這一點不是由法描述符來表達的。參數this的傳遞,是由Java虛擬機實現在調用實例方法所使用的指令中實現的隱式傳遞。
  • 如果一個方法描述符是有效的,那麼它對應的方法的參數列表總長度小於等於255,對於實例方法和接口方法,需要額外考慮隱式參數this。參數列表長度的計算規則如下:每個long和double類參數長度爲2,其餘的都爲1,方法參數列表的總長度等於所有參數的長度之和。(引入限制,方法的參數最多有255個)

4.4 常量池

  • Java虛擬機指令執行時不依賴與類、接口,實例或數組的運行時佈局,而是依賴常量池(constant_pool)表中的符號信息。
  • !!!各種重要的常量結構體!!!

4.10.2.5 異常和finally

  • 如果try語句中遇到了return,代碼的行爲如下:

    1. 如果有返回值的話,將返回值保存在局部變量中。
    2. 執行jsr指令將控制權轉到給finally語句中。
    3. 在finally執行完成後,返回事先保存在局部變量中的值。
  • 如果在try語句中有異常拋出,異常處理器的行爲是:

    1. 將異常保存在局部變量中。
    2. 執行jsr指令將控制權轉到給finally語句中。
    3. 在執行完finally語句後,重新拋出這個事先保存好的異常。

4.11 Java虛擬機限制

    1. 每個類或接口的常量池項最多爲65535個
    1. 方法調用時創建的棧幀的局部變量表中的最大局部變量個數65535個
    1. 類或接口中可以聲明的字段數最多爲65535個
    1. 類或接口中可以聲明的方法數最多爲65535個
    1. 類或接口的直接父接口最多爲65535個
    1. 方法棧幀(§2.6)中的操作數棧的大小深度爲65535
    1. 數組的維度最大爲255維
    1. 方法的參數最多有255個
    1. 字段和方法名稱、字段和方法描述符以及其它常量字符串值(由ConstantValue屬性(§4.7.2)引用的值)最大長度爲65535個字符

5.3 創建和加載

  • Java虛擬機支持兩種類加載器:Java虛擬機提供的引導類加載器(Bootstrap Class Loader)和用戶自定義類加載器(User-Defined Class Loader)。每個用戶自定義的類加載器應該是抽象類ClassLoader的某個子類的實例。應用程序使用用戶自定義類加載器是爲了便於擴展Java虛擬機的功能,支持動態加載並創建類。當然,它也可以從用戶自定義的數據來源來獲取類的二進制表示並創建類。例如,用戶自定義類加載器可以通過網絡下載、動態產生或是從一個加密文件中提取類的信息。
  • 在Java虛擬機運行時,類或接口不僅僅是由它的名稱來確定,而是由一個值對:二進制名稱(§4.2.1)和它的定義類加載器共同確定。每個這樣的類或接口都歸屬於獨立的運行時包結構(Runtime Package)。類或接口的運行時包結構由包名及類或接口的定義類加載器來決定。

5.4 鏈接

  • 驗證(Verification,§4.10)階段用於確保類或接口的二進制表示結構上是正確的。
  • 準備(Preparation)階段的任務是爲類或接口的靜態字段分配空間,並用默認值初始化這些字段(§2.3,§2.4)。這個階段不會執行任何的虛擬機字節碼指令。在初始化階段(§5.5)會有顯式的初始化器來初始化這些靜態字段,所以準備階段不做這些事情。
  • 解析(Resolution)是根據運行時常量池的符號引用來動態決定具體的值的過程。

5.5 初始化

  • 初始化(Initialization)對於類或接口來說,就是執行它的初始化方法(§2.9)。在發生下列行爲時,類或接口將會被初始化:
    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.7 Java虛擬機退出

  • Java虛擬機的退出條件一般是:某些線程調用Runtime類或System類的exit方法,或是Runtime類的halt方法,並且Java安全管理器也允許這些exit或halt操作。除此之外,在JNI(Java Native Interface)規範中還描述了當使用JNI API來加載和卸載(Load & Unload)Java虛擬機時,Java虛擬機的退出過程。

第6章 Java虛擬機指令集

第7章 操作碼助記符

參考鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章