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

JVM 內存區域與溢出分析:運行時數據區、OOM 場景、對象實例化內存視圖

     編輯:Java 綜合教學

JVM 內存區域與溢出分析:運行時數據區、OOM 場景、對象實例化內存視圖

理解 JVM 內存結構是排查 OOM、調優 GC 的基石。本文依據 JVM 規範劃分 5 大運行時數據區,補充直接內存,並給出各區域 OOM 觸發代碼、對象創建內存佈局、訪問方式對比。

一、五大運行時數據區

區域線程性質核心內容OOM 條件
程序計數器私有字節碼行號指示器規範定義無 OOM
虛擬機棧私有棧幀(局部變量表、操作數棧、動態鏈接、返回地址)棧深度溢出 → StackOverflowError;擴展失敗 → OOM
本地方法棧私有Native 方法調用同虛擬機棧
Java 堆共享幾乎所有對象實例、數組無內存可分配且無法擴展 → OOM
方法區共享類信息、常量、靜態變量、JIT 編譯代碼、運行時常量池無法滿足分配 → OOM

二、直接內存

  • 非 JVM 運行時數據區,NIO ByteBuffer.allocateDirect() 向 OS 申請。
  • 不受堆大小限制,受物理內存與 CPU 位寬限制。
  • 避免堆外拷貝提升性能,但可能導致 OOM(MaxDirectMemorySize 控制)。

三、各區域 OOM 觸發代碼模板

1. 堆 OOM

-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
List list = new ArrayList<>();
while (true) list.add(new byte[1024 * 1024]); // 1MB 對象

2. 虛擬機棧 OOM(多線程)

-Xss256k
while (true) new Thread(() -> { try { Thread.sleep(10000); } catch (Exception e) {} }).start();

3. 方法區 OOM(運行時常量池/類元信息)

-XX:PermSize=10m -XX:MaxPermSize=10m (JDK 7)
-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m (JDK 8+)
// 不斷生成類:CGLIB/動態代理/JSP 編譯
while (true) Enhancer.create(Object.class, MethodInterceptor.class);

4. 直接內存 OOM

-Xmx20m -XX:MaxDirectMemorySize=10m
ByteBuffer.allocateDirect(1024 * 1024); // 循環分配

四、對象實例化內存視圖

Object obj = new Object();

涉及三區:

  1. Java 棧:局部變量表存 reference(obj)。
  2. Java 堆:存對象實例數據(對象頭 + 實例數據 + 對齊填充)。
  3. 方法區:存類型信息(類對象、父類、接口、方法表等),堆中對象頭指向此處。

五、對象訪問方式

方式原理優點HotSpot 採用
句柄池reference → 句柄池 → 實例/類型信息對象移動只改句柄,reference 穩定否
直接指針reference → 實例地址(對象頭含類型指針)少一次間接訪問,速度快是

六、內存洩漏 vs 內存溢出

  • 洩漏:對象不再使用但 GC 無法回收(如靜態集合持有、監聽器未移除、ThreadLocal 未清理),長期積累導致溢出。
  • 溢出:申請內存超過系統上限(含動態擴展)。

七、多線程棧內存權衡

-Xss 設置單線程棧大小。棧越大 → 可建線程越少。進程內存 = 堆 + 方法區 + 直接內存 + 線程數 × 棧大小 + OS 開銷。線程過多導致 OOM 時,若不能減線程,需減小 -Xmx 或 -Xss 換取更多線程槽位。

掌握內存區域邊界與 OOM 特徵,配合 jmap/jstack/jstat/Arthas 等工具,可快速定位生產環境內存問題。

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