JVM
[來源:維基百科]
程式計數器
- 程式計數器是目前線程執行的位元組碼的行号訓示器;
- 程式計數器線程私有;
- 程式計數器是JVM 規範中唯一一個沒有任何OutOfMemoryError 的區域;
虛拟機棧
- 線程私有,生命周期與線程相同;
- 虛拟機棧描述的是Java 方法執行的記憶體模型,每個方法在執行時會建立一個棧幀用于存儲局部變量表,操作數棧,動态連結,方法出口等資訊。一個方法從調用到執行,就對應着一個棧幀從入棧到出棧的過程。對于一個棧幀來說執行引擎來說,如果一個方法調用鍊很長,調用其中一個方法,其他好多方法也可能處于執行狀态,這時引擎會認為虛拟機棧頂的棧幀才是有效的,這個棧幀被稱為目前棧,這個棧幀對應的方法稱為目前方法,引擎的所有指令都是針對于目前棧幀進行操作的;
- 局部變量表,是一組變量值的存儲空間,存儲機關是slot。若是執行個體方法,則第0 個slot 存儲的是指向所有執行個體對象的引用,在方法中可以通過this 來通路這個隐含的參數,接着存儲的是參數,然後是方法内的局部變量;
- 操作數棧,方法執行之初為空,執行過程中會有各種位元組碼指令寫入或者彈出值。它不通過索引來通路,而是通過标準的棧操作—壓棧和出棧—來通路的,比如,如果某個指令把一個值壓入到操作數棧中,稍後另一個指令就可以彈出這個值來使用。是以操作數棧又可以了解為“基于棧的執行引擎”;
- 動态連結,運作時轉為直接引用;靜态連結,解析時(符号引用)轉化為直接引用;
- 當線程申請的棧空間大于虛拟機允許的深度時,會出現StackOverFlowError 異常;當虛拟機棧無法申請到足夠記憶體時,會出現OutOfMemoryError 異常;
本地方法棧
同上,為native 方法服務;
堆
- 線程共享;
- 用來存儲執行個體對象與數組對象;
- 由于現在有了逃逸分析技術,也可以将對象配置設定到棧上;
- “垃圾堆”,Java 堆是GC 的主要區域,主要采用分代回收,有年輕代,老年代;
- Java 堆,實體上可以不連續,邏輯上要求連續;
- 記憶體配置設定,碰撞指針(要求記憶體絕對規整,注意線程同步,采用CAS 原理+ 失敗重試或者本地線程配置設定緩沖),空閑清單(記憶體不規整)。選擇哪種配置設定算法取決于記憶體是否規整,是否規整取決于采用的GC 算法是否壓縮;
- 對象的通路方法,句柄 + 直接通路;
- 堆空間不足時抛出 OutOfMemoryError;
方法區
- 線程共享;
- 用于存儲已經被虛拟機加載的類的類資訊,常量,靜态變量,編譯後的代碼,運作時常量池(存儲編譯器生成的各種字面量與符号引用);
- class 檔案中的常量池在類加載之後就被放入運作時常量池;相比之下,方法區的運作時常量池具有動态性;
- 常量可以在運作期間通過intern 加入到常量池中;
- 方法區空間不足時會抛出 OutOfMemoryError;
堆外記憶體(直接記憶體)
1. 直接記憶體可以減少IO 時的記憶體複制,零拷貝(不需要堆記憶體Buffer 拷貝一份到直接記憶體);
2. 無gc;
優點:
- 減少垃圾回收工作,垃圾回收會暫停其他工作(若使用多線程或者時間片方式,根本感覺不到);
- 加快複制速度,省略掉Buffer Copy To off-heap 過程;
- 難以控制,若記憶體洩露,排查難度很大;
- 不适合存儲複雜的對象;