目錄
有的人寫博客給他人看,有的人寫博客給自己看,有的人寫博客只是記錄,有的人寫博客爲了展示,我都有。寫博客還有其他的目的和作用,看客可以自己用心體驗。
寫博客特別累,不是碼字類,而是看書動腦子累。今天打破下長時間的沉默,發表點大家常常掛在嘴邊的東西。
程序計數器(PC寄存器)
“線程私有”的內存區域,每條線程有一個。
存放的是正在執行的字節碼指令(在第三部分有講,方法會編譯成字節碼集存儲在方法表集合的屬性表集合裏“Code”屬性表的code屬性裏)的地址;若線程正在執行的是java方法,則存放的是該方法中對應的字節碼指令地址,若正在執行的是native方法,則其值爲未定義的值。
Java虛擬機棧
“線程私有”,生命週期和線程一樣。
描述java方法執行時的內存模型。爲每個執行的方法創建一個棧幀用於存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。
存儲局部變量表存放各種編譯期可知的各種基本類型、對象引用(可能是對象起始地址,也可能是代表對象的句柄,還可能是對象相關的位置)、返回地址(指向了一條字節碼的地址)。局部變量表在幀中所需的內存空間在編譯期間就完全確定。
線程請求的棧深度大於虛擬機所允許的深度,拋出StackOverflowError異常;線程動態擴展棧的空間超過虛擬機規範所允許的固定長度,拋出OutOfMemoryError異常。
本地方法棧
“線程私有”。
本地方法棧也會拋出StackOverflowError異常和OutOfMemoryError異常。幀怎麼實現?
Java堆
線程共享。
物理空間可以不連續,邏輯空間連續即可。可擴展,但通過-Xmx和-Xms控制,超過時拋出OutOfMemoryError異常。其中各個區域的劃分,分配,回收參見“垃圾收集器與內存分配策略”部分。
方法區
線程共享。
存儲已被虛擬機加載的類信息(包含Class文件中的常量池)、常量、靜態變量、即時編譯器編譯後的代碼等。別名Non-Heap。
本質上和“永久代”並不等價,只能說HotSpot虛擬機的一些版本把GC分代收集區域擴展至方法區。然而方法區可以選擇不實現垃圾收集。
HotSpot虛擬機可以通過下面的參數來限制“永久代”的大小(方法區大小限制[包括運行時常量池的大小限制])。
運行時常量池是方法區的一部分。Class文件中的常量池包含編譯期生成的各種字面量和符號引用,這些內容在類加載後存在方法區的運行時常量池,這個池子還會存儲翻譯出來的直接引用。Java虛擬機規範並沒有對該池做任何要求,編譯期的常量可以存放,運行期的常量也可以存放,例如:String的intern方法。
物理空間可以不連續,邏輯空間連續即可。可以選擇固定的大小或者可擴展,超出時拋出OutOfMemoryError異常。
直接內存
不是運行時數據區域的一部分,也不是java虛擬機規範中的定義的內存區域,不受java堆大小的限制。例如可以通過存儲在java堆中的DirectByteBuffer對象作爲這塊直接內存的引用來進行操作,或者通過JNI來分配直接內存來使用。
/**
* VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M
* @author zzm
*/
public class DirectMemoryOOM {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) throws Exception {
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
while (true) {
unsafe.allocateMemory(_1MB);
}
}
}
對象內存佈局
對象在內存中的佈局分爲3塊區域:對象頭(Header)、實例數據(Instance Data)和對齊填充。
對象頭有2部分信息:自身的運行時信息,哈希碼,GC分代年齡,鎖狀態標誌,線程持有的鎖等,具體查書;對象類型數據指針。
實例數據是各種類型的字段的內容。有存儲順序的策略一講。
從對象起始地址起8字節對齊,不足填充。
對象訪問定位
目前主要有2種訪問方式:
珍惜他人勞動成果,筆記轉載時,請掛上本文鏈接。