JVM內(nèi)存區(qū)域
jvm 按照線程安全進(jìn)行分類:
- 線程私有: 程序計數(shù)器,Java虛擬機(jī)棧,本地方法棧
- 線程共享: Java堆,方法區(qū),運行時常量池,直接內(nèi)存(嚴(yán)格來說不是屬于JVM的一部分)
程序計數(shù)器
字節(jié)碼解釋器通過這個計數(shù)器來選擇下一條要執(zhí)行字節(jié)碼指令。程序計數(shù)器是唯一一個不會出現(xiàn)OOM的內(nèi)存區(qū)域
Java虛擬機(jī)棧
虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存區(qū)域,每個方法執(zhí)行的同時會創(chuàng)建一個棧幀,棧幀用于存儲局部變量表,操作數(shù)棧,動態(tài) 鏈表,方法出口等
局部變量表用于存儲編譯期的各種基本數(shù)據(jù)類型,對象引用,這里常常跑出的異常是StackOverFlowError
Java堆
存放對象,現(xiàn)代的Jvm實現(xiàn)一般都會在JAVA堆上進(jìn)行分代存儲,這樣能更加優(yōu)于GC時的效率 Eden(新生代)
方法區(qū)
用于存儲已加載過的類的信息,常量,靜態(tài)變量,即時編譯器編譯后的代碼等數(shù)據(jù)
運行時常量池
運行時常量池是方法區(qū)的一部分
虛擬機(jī)中的對象
對象的創(chuàng)建
- 加載對應(yīng)的類: 碰到
new關(guān)鍵字,確定對應(yīng)的 類是否加載過,如果沒有加載,加載對應(yīng)的類 - 分配空間: 類加載過程中,會確定,類對應(yīng)的對象的存儲信息等
內(nèi)存分配的動作按照 線程劃分在每個線程的 Thread local allocation buffer 中,用于頻繁創(chuàng)建對象的緩存 - 設(shè)置對象的必要信息: HashCode,鎖信息,GC分代信息等
對象的內(nèi)存布局
對象在內(nèi)存中分為三塊區(qū)域: 對象頭,實例數(shù)據(jù),對齊填充
- 對象頭: 存儲HashCode,GC分代年齡,鎖狀態(tài)標(biāo)志,線程持有的鎖,偏向線程ID,偏向時間戳,類型指針,如果是數(shù)組,還有一塊存儲數(shù)組長度的信息
對象的訪問定位
Java程序需要通過棧上的reference數(shù)據(jù)來操作堆上的具體對象
- 句柄訪問: java堆上開辟一塊存儲區(qū)域?qū)iT作為句柄池,句柄中包含了 實例數(shù)據(jù)與類型數(shù)據(jù)各自的具體地址信息
- 直接地址訪問
區(qū)別: 使用句柄訪問的好處是reference中存儲的穩(wěn)定的句柄地址,在對象被移動(GC 過程),只會改變實例數(shù)據(jù)指針,而reference本身不會改變。 但是相對于直接指針訪問會比較慢2