JVM-字節碼

字節碼是編譯後的文件,格式固定,對一些個人認爲關鍵的屬性做一些總結:

1、兩個類在編譯成Class之後就不存在任何聯繫了。如果只修改一個字節碼文件,對運行時可能會有影響,最好重新進行編譯。

2、指向常量池的索引值爲0的數據,說明它不引用任何常量池項。

3、指令碼+操作數,操作數來源於操作數棧或者局部變量表,操作數棧存儲棧幀計算的中間結果。32位的字節,由虛擬機內部實現。

4、重載本質:編譯器通過參數的靜態類型決定重載版本,編譯期決定。

    重寫本質:invokevirtual指令把常量池裏類方法的符號引用解析到了不同的直接引用上。

5、如果當前字節碼PC計數器的值已經超出了某個變量的作用域,那這個變量對應的Slot就可以交給其他變量使用。

6、字段表集合中不會列出從超類或者父接口中繼承而來的字段,但是內部類中爲了保持對外部類的訪問性,會自動添加指向外部類實例的字段。

7、方法表集合中不會出現來自父類的方法信息,重寫(Override)除外。

8、接口或者抽象類中的方法就不存在Code屬性。

9、用描述符來描述方法時,按照先參數列表,後返回值的順序描述,參數列表按照參數的嚴格順序放在一組小括號“()”之內。

10、代碼級方法特徵簽名包括:方法名稱、參數順序及參數類型,字節碼級別方法簽名還包括了返回值以及受查異常表。

11、max_stack:操作數棧深度的最大值。在方法執行的任意時刻,操作數棧都不會超過這個深度。JVM運行時需要根據這個值來分配棧幀(Stack Frame)中的操作棧深度。

12、Exceptions屬性是在方法表中與Code屬性平級的一項屬性,列舉出方法中可能拋出的受查異常(Checked Excepitons),也就是方法描述時在throws關鍵字後面列舉的異常。

13、局部變量在字節碼的作用域範圍:生命週期開始的字節碼偏移量(start_pc)、範圍覆蓋的長度(length),index是這個局部變量在棧幀局部變量表中Slot的位置。

14、StackMapTable屬性中包含零至多個棧映射幀(Stack Map Frames),每個棧映射幀都顯式或隱式地代表了一個字節碼偏移量,用於表示該執行到該字節碼時局部變量表和操作數棧的驗證類型。類型檢查驗證器會通過檢查目標方法的局部變量和操作數棧所需要的類型來確定一段字節碼指令是否符合邏輯約束。

15、Signature:存儲一個方法在字節碼層面的特徵簽名,這個屬性中保存的參數類型並不是原生類型,而是包括了參數化類型的信息。擦除法所謂的擦除,僅僅是對方法的Code屬性中的字節碼進行擦除,實際上元數據中還是保留了泛型信息,這也是我們能通過反射手段取得參數化類型的根本依據。

16、方法調用:

1.invokespecial:調用構造器、私有方法和父類方法;

2.invokestatic:調用靜態方法;

3.invokevirtual:調用虛方法,一般的實例方法都是invokevirtual調用;

4.invokeinterface:調用接口類的方法;

5.invokedynamic,java中對動態語言的支持。 

6.invokevirtual和invokeinterface通過第一個參數查找方法,動態分派,從而實現多態。

17、數組:

數組類的可見性與它的組件類型的可見性一致,如果組件類型不是引用類型,那數組類的可見性將默認爲public。

Java語言中對數組的訪問比C/C++相對安全是因爲這個類封裝了數組元素的訪問方法,而C/C++直接翻譯爲對數組指針的移動。

越界檢查不是封裝在數組元素訪問的類中,而是封裝在數組訪問的xaload、xastore字節碼指令中。

數組類的元素類型(Element Type,指的是數組去掉所有維度的類型)最終是要靠類加載器去創建

18、局部變量表與操作數棧,兩者的大小都是在編譯時確定的,因此,一個方法的棧幀的大小也是固定不變的。
局部變量表數組索引從0開始,所表示的變量是this,即是當前實例的引用。局部變量表中的Slot是否還存有關於對象的引用,否則被回收。
每個方法都在操作數棧和局部變量數組之間交換數據,並且壓入或者彈出其他方法返回的結果,局部變量數組和操作數棧之間的數據傳輸是使用通過大量的load指令(aload,iload)和store指令(astore,istore)來實現的,如aload_0: 把局部變量數組中索引爲#0的變量添加到操作數棧上。


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