Java 內存區域劃分為 線程私有 (程序計數器、虛擬機棧、本地方法棧) 與 線程共享 (堆、方法區/元空間、直接內存)。理解各區域職責、分配規則、溢出場景、GC 關係,是排查 OOM、優化性能、寫出高質量代碼的基石。本文結合 JVM 規範、HotSpot 實現、實戰案例,繪製全景圖。
+-------------------------+ ← 線程共享 | Heap (堆) | 新生代 Eden/S0/S1 + 老年代 + (JDK7- 永久代) | - Young Gen (Eden/S) | 所有 new 對象、數組分配於此 | - Old Gen | GC 主戰場 +-------------------------+ | Metaspace (元空間) | ← JDK8+ 替換永久代,存類元數據、常量、靜態變量、JIT代碼 | (原 Method Area/永久代) | 本地內存,受 -XX:MaxMetaspaceSize 限制 +-------------------------+ | Direct Memory (直接內存) | NIO ByteBuffer.allocateDirect,不受堆限制,受 -XX:MaxDirectMemorySize +-------------------------+ +-------------------------+ ← 線程私有 (每線程一份) | VM Stack (虛擬機棧) | 棧幀:局部變量表、操作數棧、動態連接、方法返回地址 | - 局部變量表 (基本類型、引用、returnAddress) | | - 基本類型八種 + 引用 (32/64位) 存此處,對象實體在堆 | +-------------------------+ | Native Stack (本地方法棧) | Native 方法調用 +-------------------------+ | PC Register (程序計數器) | 當前字節碼指令地址 +-------------------------+
-XX:SurvivorRatio);-XX:PretenureSizeThreshold) → 長期存活晉升老年代 (-XX:MaxTenuringThreshold) → 動態年齡判斷 → 空間擔保;java.lang.OutOfMemoryError: Java heap space —— 堆不夠或洩漏 (靜態集合持有、ThreadLocal 未清理、緩存無淘汰)。StackOverflowError (遞歸過深、循環調用) / OutOfMemoryError (線程過多、棧過大 -Xss);-XX:MetaspaceSize (初始觸發 GC 閾值)、-XX:MaxMetaspaceSize (上限);| 維度 | 運行時常量池 (Method Area) | 字符串常量池 (Heap, JDK7+) |
|---|---|---|
| 來源 | Class 文件常量池 (編譯期常量、符號引用) | 字符串字面量、String.intern() 手動入池 |
| 動態性 | 類加載時創建,ldc 指令訪問 | 運行時可擴充,String.intern() 返回池中引用 |
| GC 關係 | 隨類卸載回收 | 引用計數/可達性分析回收 (JDK7+ 在堆中) |
ByteBuffer.allocateDirect(capacity) 分配堆外內存,避免 Java 堆 ↔ Native 堆拷貝,提升 I/O 性能;-Xmx 限制,受 -XX:MaxDirectMemorySize (默認 = -Xmx) 限制;Cleaner (PhantomReference) → GC 觸發 → freeMemory,**釋放不及時易 OOM**;ReferenceCountUtil.release) 更可控。String s1 = "a" + "b" + "c"; // 1 個 (編譯期優化為 "abc",常量池)
String s2 = new String("a") + "b"; // 2-3 個 (new String("a") 堆對象 + 拼接產生 StringBuilder + toString 堆對象)
String s3 = "ab";
String s4 = new String("ab");
s3 == s4; // false (引用不同)
s3.equals(s4); // true (值相同)
s4.intern() == s3; // true (intern 返回常量池引用)
核心口訣:字面量進常量池,new 進堆,拼接有變量進堆,編譯期全常量進常量池。
jstat -gcutil / jmap -histo / jmap -dump:live,format=b,file=heap.hprof;-Xlog:gc*:file=gc.log:time,uptime,level:filecount=10,filesize=100M (JDK9+);-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dumps。Java 內存模型 = 棧管運行 (幀、局部變量、引用) + 堆管存儲 (對象、數組、字符串池) + 元空間管元數據 (類、常量、靜態) + 直接內存管 I/O 零拷貝。掌握分配規則、溢出特徵、GC 觸發條件,配合工具鏈,即可從容應對生產環境內存疑難雜症。