Java記憶體區域劃分及物件的訪問方式
JVM 記憶體區域劃分
JVM 記憶體區域劃分如圖:
下面對以上劃分具體講解:
- 程式計數器
程式計數器用來指示當前位元組碼執行到第幾行。每個計數器只能記錄一個執行緒的行號,所以他是執行緒私有的。
當程式執行Java方法時,其記錄當前執行指令地址;
當執行本地(native,使用c語言編譯)方法時,其值為 Undefined
由於其單一功能,它是唯一一個沒有記憶體溢位(OutOfMemoryError)的區域.
- 虛擬機器棧
一個執行緒的每一個方法在執行的同時,都會在虛擬機器棧建立對應的棧幀。方法的呼叫和完成對應著棧幀在虛擬機器棧中的入棧與出棧。
棧幀
區域性變量表 :存放方法的區域性變數(基本資料型別,物件的引用 reference
,返回地址等)
其中只有 long
和 double
佔用兩個區域性變數空間(slot),其他都是一個區域性變數空間。
區域性變量表在編譯時就已經確定,方法執行所需要分配的空間在棧幀中完全確定,在方法的整個生命週期都不會發生改變。
區域性變數空間 slot
:對於32位機器,1 slot = 32 bit
異常:當請求棧深度大於JVM允許棧深度時,丟擲 StackOverFlowError
(棧溢位)異常;由於棧深度可動態改變,直至記憶體不足時會丟擲 OutOfMemoryError
每個執行緒都對應一個虛擬機器棧,因此也是執行緒私有的。
- 本地方法棧
同上,唯一區別是本地方法棧執行 native
方法。
- 堆區(Heap)
是JVM中最重要最大的區域。所有執行緒共享。用來儲存物件例項。會丟擲OutOfMemoryError:Iava heap space
(記憶體溢位)異常
- 方法區(Method Area)
方法區在JDK1.6版本HotSpot虛擬機器中被設計為永久代,可能會在後續設計中取消。
方法區用來儲存虛擬機器載入的類資訊(版本,field,方法,介面等),靜態變數,編譯器即時編譯程式碼等。
對方法區的垃圾回收操作主要集中在對常量池的記憶體回收以及對已載入類的解除安裝。
會丟擲OutOfMemoryError:PermGen space
(記憶體溢位)異常
執行時常量池(Runtime Constant Pool)
1. 儲存編譯期就生成的字面常量,符號引用,翻譯後的直接引用。
符號引用:編碼是用字串表示某個變數,介面的位置等
直接引用:經過翻譯的地址。在類連結階段完成翻譯
2. 儲存執行時產生的常量,比如 String.intern()
方法,該方法判斷常量池中有沒有已存在的字串常量,沒有則新建,有則返回地址。
- 直接記憶體
JDK基於通道(Channel)和緩衝區(Buffer)的記憶體分配方式。假設機器有4G記憶體,1G被JVM佔用,則剩餘3G為直接記憶體。
JVM中物件訪問方式
以Object obj = new Object()
為例:Object obj 作為一個本地引用(reference)儲存在虛擬機器棧中的本地變量表中。
new Object() 作為物件例項儲存在堆中。Object類的型別資訊資料儲存在方法區中。
常見的物件訪問有兩種:
1. 控制代碼訪問
如下圖所示:
在這種訪問方式中,JVM堆中會有專門的一塊區域作為控制代碼池。這種方法的優點是穩定
2. 直接指標訪問
如下圖所示:
此種方式中,JVM堆中儲存的物件資訊包含了在方法區中相應的型別資料地址。其優勢在於速度快。而在HotSpot虛擬機器中就用的這種方式。