天天看點

Java - 簡述JVM 記憶體模型

JVM

Java - 簡述JVM 記憶體模型

[來源:維基百科]

程式計數器

  • 程式計數器是目前線程執行的位元組碼的行号訓示器;
  • 程式計數器線程私有;
  • 程式計數器是JVM 規範中唯一一個沒有任何OutOfMemoryError 的區域;

虛拟機棧

  • 線程私有,生命周期與線程相同;
  • 虛拟機棧描述的是Java 方法執行的記憶體模型,每個方法在執行時會建立一個棧幀用于存儲局部變量表,操作數棧,動态連結,方法出口等資訊。一個方法從調用到執行,就對應着一個棧幀從入棧到出棧的過程。對于一個棧幀來說執行引擎來說,如果一個方法調用鍊很長,調用其中一個方法,其他好多方法也可能處于執行狀态,這時引擎會認為虛拟機棧頂的棧幀才是有效的,這個棧幀被稱為目前棧,這個棧幀對應的方法稱為目前方法,引擎的所有指令都是針對于目前棧幀進行操作的;
  • 局部變量表,是一組變量值的存儲空間,存儲機關是slot。若是執行個體方法,則第0 個slot 存儲的是指向所有執行個體對象的引用,在方法中可以通過this 來通路這個隐含的參數,接着存儲的是參數,然後是方法内的局部變量;
  • 操作數棧,方法執行之初為空,執行過程中會有各種位元組碼指令寫入或者彈出值。它不通過索引來通路,而是通過标準的棧操作—壓棧和出棧—來通路的,比如,如果某個指令把一個值壓入到操作數棧中,稍後另一個指令就可以彈出這個值來使用。是以操作數棧又可以了解為“基于棧的執行引擎”;
  • 動态連結,運作時轉為直接引用;靜态連結,解析時(符号引用)轉化為直接引用;
  • 當線程申請的棧空間大于虛拟機允許的深度時,會出現StackOverFlowError 異常;當虛拟機棧無法申請到足夠記憶體時,會出現OutOfMemoryError 異常;

本地方法棧

同上,為native 方法服務;

  • 線程共享;
  • 用來存儲執行個體對象與數組對象;
  • 由于現在有了逃逸分析技術,也可以将對象配置設定到棧上;
Java - 簡述JVM 記憶體模型
  • “垃圾堆”,Java 堆是GC 的主要區域,主要采用分代回收,有年輕代,老年代;
  • Java 堆,實體上可以不連續,邏輯上要求連續;
  • 記憶體配置設定,碰撞指針(要求記憶體絕對規整,注意線程同步,采用CAS 原理+ 失敗重試或者本地線程配置設定緩沖),空閑清單(記憶體不規整)。選擇哪種配置設定算法取決于記憶體是否規整,是否規整取決于采用的GC 算法是否壓縮;
  • 對象的通路方法,句柄 + 直接通路;
  • 堆空間不足時抛出 OutOfMemoryError;

方法區

  • 線程共享;
  • 用于存儲已經被虛拟機加載的類的類資訊,常量,靜态變量,編譯後的代碼,運作時常量池(存儲編譯器生成的各種字面量與符号引用);
  • class 檔案中的常量池在類加載之後就被放入運作時常量池;相比之下,方法區的運作時常量池具有動态性;
  • 常量可以在運作期間通過intern 加入到常量池中;
  • 方法區空間不足時會抛出 OutOfMemoryError;

堆外記憶體(直接記憶體)

1. 直接記憶體可以減少IO 時的記憶體複制,零拷貝(不需要堆記憶體Buffer 拷貝一份到直接記憶體);

2. 無gc;

優點:

  • 減少垃圾回收工作,垃圾回收會暫停其他工作(若使用多線程或者時間片方式,根本感覺不到);
  • 加快複制速度,省略掉Buffer Copy To off-heap 過程;
  • 難以控制,若記憶體洩露,排查難度很大;
  • 不适合存儲複雜的對象;