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

JVM 運行時數據區域深度解析:程序計數器、虛擬機棧、堆、方法區與對象訪問

     編輯:Java 綜合教學

概述

Java 虛擬機在執行程序時,將管理的內存劃分為若干個數據區域。每個區域有特定用途、創建與銷毀時機。理解這些區域是排查 OOM、優化性能、掌握 GC 原理的基礎。本文基於 JDK 8 之前的經典模型(含永久代)進行詳細講解。

運行時數據區域總覽

JVM 運行時數據區域圖

一、程序計數器

  • 特點:線程私有、內存極小、唯一不拋出 OutOfMemoryError 的區域。
  • 作用:當前線程執行的字節碼行號指示器。分支、循環、跳轉、異常處理、線程恢復均依賴它。
  • 值:執行 Java 方法時指向字節碼指令地址;執行 Native 方法時為 undefined。

二、Java 虛擬機棧

  • 生命周期:與線程同步,線程私有。
  • 棧幀:每個方法調用對應一個棧幀,包含局部變量表、操作數棧、動態鏈接、方法出口。
  • 局部變量表:存放編譯期可知的基本類型、對象引用、returnAddress。大小在編譯期確定,運行期不變。long/double 佔 2 Slot,其餘 1 Slot。
  • 異常:
    • StackOverflowError:棧深度超過限制(遞歸過深)。
    • OutOfMemoryError:動態擴展時無法申請足夠內存。

三、本地方法棧

與虛擬機棧類似,但服務於 Native 方法(JNI 調用)。HotSpot 將兩者合併實現。同樣可能拋出上述兩種異常。

四、Java 堆

  • 地位:JVM 管理的最大內存區域,所有線程共享,啟動時創建。
  • 用途:存放對象實例(幾乎所有對象)。隨著 JIT 編譯與逃逸分析成熟,棧上分配、標量替換使「對象必須在堆上」不再絕對。
  • GC 主戰場:堆是垃圾收集器管理的核心區域,故稱「GC 堆」。
  • 分代結構:新生代 + 老年代。新生代細分 Eden、From Survivor、To Survivor。
  • 內存分配:邏輯連續、物理可不連續。主流 JVM 可擴展實現(-Xms/-Xmx)。無法分配時拋出 OutOfMemoryError。

五、方法區

  • 共享區域:存儲已加載的類信息、常量、靜態變量、JIT 編譯後的代碼。
  • 別名:Non-Heap(非堆),區別於 Java 堆。
  • 規範寬鬆:可固定大小、可擴展、可不實現 GC。
  • GC 行為:較少,主要針對常量池回收與類型卸載。回收條件苛刻,效果難以滿意。
  • 異常:無法滿足內存分配時拋出 OutOfMemoryError。

六、運行時常量池

  • 屬於方法區一部分。
  • Class 文件常量池存放編譯期字面量與符號引用;類加載後進入運行時常量池。
  • 動態性:運行期可添加新常量(如 String.intern())。
  • 受方法區內存限制,不足時拋出 OutOfMemoryError。

七、對象訪問定位

代碼 Object obj = new Object(); 涉及三大區域:

  • Java 棧:obj 引用存放在局部變量表(reference 類型)。
  • Java 堆:new Object() 分配實例數據,含對象頭、實例數據、對齊填充。
  • 方法區:存放類型信息(類元數據),堆中對象頭包含指向方法區類型的指針。

主流訪問方式

方式原理優點缺點
句柄訪問 堆劃分句柄池,reference→句柄地址,句柄→實例/類型地址 對象移動時只改句柄,reference 穩定 雙重間接訪問,速度較慢
直接指針 reference 直接存對象地址,對象頭含類型指針 節省一次指針定位,速度快(HotSpot 採用) 對象移動需更新 reference

句柄訪問示意圖

直接指針訪問示意圖

總結

掌握 JVM 內存結構是 Java 進階的必經之路。程序計數器與棧隨線程生死,堆與方法區隨進程;堆是 GC 核心,方法區存類元數據;對象訪問方式影響性能,HotSpot 採用直接指針。理解這些為後續學習 GC 算法、調優參數、排查內存洩漏打下堅實基礎。

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