一、JVM 內存模型概覽
Java 虛擬機(JVM)在運行時將內存劃分為多個區域,其中與開發者關係最密切的是:
- 棧(Stack)
- 堆(Heap)
- 方法區(Method Area,含常量池)
- 程序計數器(PC Register)
- 本地方法棧(Native Method Stack)
本文聚焦於 棧 和 堆。
二、棧內存(Stack Memory)
1. 特點
- 線程私有:每個線程擁有獨立的棧。
- 生命週期短:隨方法調用而創建,隨方法結束而銷燬。
- 存儲內容:
- 局部變量(基本類型:
int,boolean等) - 對象的引用(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,避免動態擴容帶來的性能抖動。