一、JVM 內存模型概覽

Java 虛擬機(JVM)在運行時將內存劃分為多個區域,其中與開發者關係最密切的是:

  • 棧(Stack)
  • 堆(Heap)
  • 方法區(Method Area,含常量池)
  • 程序計數器(PC Register)
  • 本地方法棧(Native Method Stack)

本文聚焦於

二、棧內存(Stack Memory)

1. 特點

  • 線程私有:每個線程擁有獨立的棧。
  • 生命週期短:隨方法調用而創建,隨方法結束而銷燬。
  • 存儲內容
  • 局部變量(基本類型:intboolean 等)
  • 對象的引用(reference,即“指針”)
  • 方法調用的棧幀(Stack Frame),包含參數、返回地址等

2. 內存分配方式

  • 連續內存塊,採用“先進後出”(LIFO)結構。
  • 分配和回收速度極快(只需移動棧頂指針)。

3. 示例代碼

public void method() {
    int a = 10;               // 存在棧中
    String str = "Hello";     // str 是引用,存在棧中;"Hello" 對象在堆或字符串常量池
    MyClass obj = new MyClass(); // obj 引用在棧,MyClass 實例在堆
}

4. 常見異常

  • StackOverflowError:遞歸過深或無限遞歸導致棧溢出。
public void infiniteRecursion() {
    infiniteRecursion(); // 無終止條件 → StackOverflowError
}

5. 調整棧大小

通過 JVM 參數 -Xss 設置每個線程的棧大小(默認通常為 1MB):

java -Xss512k MyApp

三、堆內存(Heap Memory)

1. 特點

  • 線程共享:所有線程共用同一塊堆內存。
  • 生命週期長:對象在堆中創建,直到被垃圾回收器(GC)回收。
  • 存儲內容
  • 所有通過 new 創建的對象實例
  • 數組(無論元素是基本類型還是引用類型)

2. 內存結構(以 HotSpot JVM 為例)

現代 JVM 將堆分為:

  • 新生代(Young Generation)
  • Eden 區
  • Survivor 區(S0, S1)
  • 老年代(Old Generation)
  • (JDK 8+ 移除了永久代,改用元空間 Metaspace 存儲類信息)

對象優先在 Eden 區分配,經過多次 GC 後存活的對象進入老年代。

3. 示例

MyClass obj = new MyClass();
// obj(引用)→ 棧
// new MyClass()(對象實例)→ 堆

4. 常見異常

  • java.lang.OutOfMemoryError: Java heap space:堆內存不足,無法分配新對象。
  • 原因:內存泄漏、堆太小、大對象頻繁創建等。

5. 調整堆大小

常用 JVM 參數:

  • -Xms:初始堆大小(如 -Xms512m
  • -Xmx:最大堆大小(如 -Xmx2g

建議生產環境設置 -Xms == -Xmx,避免動態擴容帶來的性能抖動。