簡單介紹Inside JVM體系結構
當Inside JVM運行程序時,字節碼,創建的對象,傳遞給方法的參數,返回值,局部變量以及運算的中間結果保存在運行時數據區中。規范本身對運行時數據區只有抽象的描述,也使得JVM可以容易的在各種計算機和設備上實現。
Inside JVM運行時數據區
1方法區:
JVM中被裝載的類型信息存儲在一個邏輯上被稱為方法區的內存中,JVM在裝載完CLASS文件后提取其中的類型信息并將之存儲在方法區。該類型的靜態變量同樣也存儲在方法區中。由于所有的線程共享方法區,所以對方法區數據的訪問必須考慮到線程的同步。
方法區的大小是不固定的,JVM可以通過裝載新類型或者卸載已有類型來動態的調整方法區的大小,即可以改變方法區所占用的內存。方法區不一定是連續的,方法區可以在一個堆中自由分配。
JVM保存的在方法區中的存儲類型以下信息
此類型的全限定名
此類型的直接超類的全限定名(除非這個類型為java.lang.object,它沒有超類)
此類型為接口還是類
此類型的訪問修飾符號(public,abstact或final的某個子集)
除以上基本信息,還得存儲以下類型的具體信息
此類型的常量池
字段信息
方法信息
除常量以外的所有靜態變量
一個到類classLoader的引用
一個到Class類的引用
常量池可以理解為本地指針數組,在JAVA的動態連接中起核心的左右,后邊再做詳細的介紹。
為了盡可能的提高訪問的效率,必須優化存儲在方法區中的類型信息的數據結構。所以,實現中還可以加如其他數據結構以加快訪問原始數據的速度,如方法表。JVM為每個裝載的非抽象類,都生成一個方法表,把他作為類信息的一部分保存在方法區。方法表也是一個本地指針數組,其元素為方法的入口地址。方法表所指向實例方法的數據包括以下信息:
此方法的操作數棧和局部變量的大小
此方法的字節碼
異常表
JVM可以為每個對象生成一份方法表的copy(這樣比較耗內存,但能提高訪問的速度)或只在對象里保存到方法區中方法表的引用。這和C++中的VTBL很象,在C++中,對象有實例數據和一組指向對象可以調用的虛擬函數指針組成。
2堆
Java程序在運行時創建的所有類室例或數組都放在同一個堆中,而一個JVM實例只有一個堆空間,所有線程都共享這個堆。堆空間可以自由的伸縮,也不必是連續的。
常見的堆空間的設計:
a.把堆空間分為兩部分:句柄池和對象池,對象的引用為指向句柄池的本地指針,句柄池里的每個條目分為兩部分,一部分為指向對象池的本地指針,一部分為指向方法區類數據區的本地指針。對象池里保存的是實例對象的數據,此數據是實例私有的。這種設計的好處有利于內存碎片的整理,當移動對象池中的對象時,句柄部分只需要修改指向對象池條目的地址。缺點就是兩級指針的訪問。
b.使對象指針直接的指向對象數據,該數據包括指向方法區方法區數據類類型的指針和對象的實例數據。這樣的優缺點正好和前邊的方法相反。當移動堆中的對象時,對象的指針也得跟著改變,這就必須在整個運行時數據區中更新被移動對象的引用。
以上兩種方法的思想可以類比為對鏈表和數組的刪除和加入操作。
在Java中,數組和其他對象一樣,總是存儲在堆中并擁有一個與他們的類向關聯的CLASS實例,所有具有相同維度和類型的數組都是一個類的實例,而不管數組的長度。
3程序記數器
每個線程都有自己的程序記數器,它的內容總是下一條將被執行指令的地址。
4Java棧
當一個線程被創建時都將得到自己的程序記數器和Java棧,Java棧以幀為單位保存調用信息。當線程調用一個方法時,JVM會壓如一新的棧幀到Java棧,反之則彈出。也就是說,JVM只會對Java棧執行兩種操作:以幀為單位的壓棧和彈棧。幀的大小根據調用信息是可變的,后邊做詳細的介紹。由于Java棧上的數據是此線程私有的,因此不需考慮多線程下的棧數據的線程安全問題。
Inside JVM棧幀由三部分組成:局部變量區,操作數棧和幀數據區。
a.局部變量區
局部變量區的大小由調用方法的參數和方法的局部變量所決定。編譯器按聲名順序將他們放到局部變量數組,此數組以字長為單位,從0開始記數。如果是實例方法,數組的第一個元素為實例的this指針。
在Java中,所有的對象都按引用傳遞,并且對象存儲在堆中,在局部變量或操作數棧中不會有對象的COPY,只有對象引用。
b操作數棧
操作數棧也是以字長為單位的數組,但不同于局部變量數組以索引去訪問,它是通過標準的棧操作,壓棧和彈棧來訪問的。JVM沒有寄存器,程序記數器也無法被程序指令直接訪問。JVM的運行方式是基于棧的而非基于寄存器的,JVM的指令是從操作數棧中而不是寄存器中取得操作數的。雖然指令也可以從其他地方取得操作數,比如從字節碼流中跟隨在操作碼之后的字節中或從常量池中,但主要還是從操作數棧中獲取操作數。
JVM把操作數棧作為它的工作區,大多數指令都要從這里彈出數據,執行運算,然后把結果壓回操作數棧,然后等相關的指令將結果再次彈出。操作數棧扮演了暫存操作數的角色。
C幀數據區
除局部變量區和操作數棧外,Java棧幀還數據來支持常量池的解析、正常方法的返回以及異常派發機制。這些信息都保存在Java棧幀的幀數據區中。JVM可以通過幀數據區中指向常量池的指針來執行某個需要用到常量池數據的指令。
5本地方法棧
當線程調用本地方法時,JVM會保持Java棧不變,不再在線程的Java棧中壓入新的幀,Inside JVM只是簡單地動態連接并直接調用本地方法。但是,本地方法有可能回調JVM中的Java方法,此時該線程會保存本地方法棧的狀態并進入Java棧,在Java棧壓入新的棧幀。
【編輯推薦】