首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JVM 記憶體結構深度解析:基於《深入理解 Java 虛擬機》學習筆記

     編輯:Java 相關知識

Java 虛擬機在執行 Java 程式的過程中,會將其管理的記憶體劃分為若干個不同的資料區域。這些區域各有專屬用途,並依據各自的生命週期規則獨立創建與銷毀資料。理解 JVM 記憶體模型是掌握 Java 效能調優與問題排查的基石。

JVM 記憶體區域劃分概覽

根據《Java 虛擬機規範》,JVM 記憶體主要劃分為線程私有區域與線程共享區域兩大類:

線程私有區域(隨線程生命週期)

  • 程式計數器
  • Java 虛擬機棧
  • 本地方法棧

線程共享區域(隨虛擬機啟動/關閉)

  • Java 堆
  • 方法區

JVM 記憶體結構圖

核心區域詳細解析

1. 程式計數器

程式計數器是一塊較小的記憶體空間,可視為當前線程所執行的字節碼行號指示器。由於 JVM 多線程是通過輪流切換線程分配 CPU 時間片來實現的,當線程被切換出去時,必須記錄下一條將要執行的指令地址,以便線程切換回來時能繼續執行。

關鍵特性:

  • 線程私有,互不干擾
  • 僅記錄 Java 方法的字節碼地址;執行 Native 方法時值為空
  • 佔用記憶體極小,是唯一不會拋出 OutOfMemoryError 的區域

2. Java 虛擬機棧

虛擬機棧描述的是 Java 方法執行的記憶體模型:每個方法被執行時都會創建一個棧幀,用於存儲局部變量表、操作數棧、動態連接、方法返回地址等信息。每個方法從調用到完成,對應一個棧幀在虛擬機棧中入棧到出棧的過程。

虛擬機棧結構

棧幀內部結構

棧幀核心組件:

  1. 局部變量表:存放方法參數與局部變量(基本類型、對象引用、returnAddress)。大小在編譯期確定,以 Slot 為單位。注意:我們平常說的「棧」,實際指的就是局部變量表。
  2. 操作數棧:方法運算的工作區,遵循後進先出原理。編譯器預計算最大深度分配空間。為優化效能,多數 JVM 實現會讓上層方法的局部變量表與下層方法的操作數棧內存重疊,減少參數傳遞的複製開銷。
  3. 動態連接:每個棧幀包含一個指向運行時常量池中該方法引用的符號引用,支持動態連接(運行期解析)。區別於靜態解析(編譯期確定目標方法,如 static、final、private 方法)。
  4. 方法返回地址:正常返回或異常拋出時,需恢復調用者執行狀態,此處保存調用者 PC 計數器值。
  5. 附加信息:JVM 規範未定義的實現特定數據。

異常場景:

  • StackOverflowError:棧深度超過 JVM 限制(如遞歸過深)
  • OutOfMemoryError:無法申請足夠記憶體擴展棧(如線程過多)

3. 本地方法棧

功能與虛擬機棧類似,區別在於服務對象:虛擬機棧服務 Java 方法(字節碼),本地方法棧服務 Native 方法(C/C++ 等)。JVM 規範未強制其結構與語言,各廠商自行實現(HotSpot 將兩者合一)。

4. Java 堆

JVM 管理的最大記憶體區域,幾乎所有對象實例與數組都在這裡分配。堆是垃圾收集器管理的主要區域(GC 堆),現代收集器多採用分代收集演算法:

Java 堆分代結構

  • 新生代:Eden + 兩個 Survivor 區,對象朝生夕死,採用複製演算法
  • 老年代:存活時間長的對象,採用標記-整理或標記-壓縮演算法

堆可物理不連續,只需邏輯連續。可通過 -Xms/-Xmx 設定初始/最大值。

5. 方法區

存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等。雖稱「永久代」,但並非永不回收:主要回收目標是常量池卸載與類型卸載(條件苛刻)。JDK 8 起移除永久代,改用元空間(本地記憶體)。

6. 運行時常量池

屬於方法區一部分。Class 文件中的常量池在類加載後進入運行時常量池,存放字面量(字符串、final 常量)與符號引用(類/接口全限定名、字段/方法名與描述符)。符號引用在類加載階段或首次使用時解析為直接引用。

常見記憶體溢出錯誤對比

錯誤類型成因典型場景
OutOfMemoryError區域數據增長導致無法申請更多物理記憶體,或達到 JVM 參數上限堆溢出、元空間溢出、直接記憶體溢出、線程過多導致棧溢出
StackOverflowError棧幀入棧深度超過 JVM 允許最大深度遞歸調用無終止條件、大量方法嵌套調用

理解各區域職責與溢出成因,是定位線上 OOM 問題、進行 JVM 調優的前提。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved