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

Java 堆與棧記憶體區別深度解析

     編輯:Java 相關知識

Java 記憶體模型:堆與棧核心差異解析

理解 Java 虛擬機中堆與棧的區別,是掌握物件生命週期、參數傳遞機制、效能調優、排查 OOM 的基礎。本文從記憶體結構、分配策略、存取速度、生命週期、常見誤區五個維度深度對比。

核心差異對比表

維度堆棧 (Java 虛擬機棧)
儲存內容物件實例、陣列、字串常量池 (JDK 7+)基本型別變數、物件引用 (指標)、方法呼叫棧幀、局部變數表、操作數棧
共享性全線程共享線程私有
分配方式動態分配 (new、反射、JNI 等)編譯期靜態決定大小 (棧幀)、運行期按序壓棧
存取速度較慢 (需指標解引用、GC 掃描)極快 (CPU 緩存友好、指針運算)
生命週期物件無引用時由 GC 回收方法執行結束自動彈出銷毀
記憶體大小大 (GB 級,-Xmx 控制)小 (MB 級,-Xss 控制,預設 1MB)
異常類型OutOfMemoryError: Java heap spaceStackOverflowError (遞歸過深/大局部變數)
碎片整理需 GC 壓縮/整理無碎片 (LIFO 分配釋放)

記憶體分配流程圖解

執行緒 T1                    執行緒 T2
┌─────────────────┐        ┌─────────────────┐
│  Stack Frame 1  │        │  Stack Frame 1  │
│  - 區域變數     │        │  - 區域變數     │
│  - 引用 ────────┼───────►│  - 引用 ────────┼──┐
└─────────────────┘        └─────────────────┘  │
                            ┌─────────────────┐  │
                            │      HEAP       │  │
                            │  ┌───────────┐  │  │
                            │  │ Object A  │◄─┘  │
                            │  └───────────┘     │
                            │  ┌───────────┐     │
                            │  │ Object B  │◄────┘
                            │  └───────────┘
                            └─────────────────┘

關鍵概念釐清

1. 參數傳遞:只有「傳值」


void modifyPrimitive(int x) { x = 10; }           // 基本型別:複製值,原值不變
void modifyRef(MyObject obj) { obj.setX(10); }    // 引用型別:複製引用,指向同一物件
void modifyRefWrong(MyObject obj) { obj = new MyObject(); } // 修改區域引用,不影響外部
  • 基本型別:棧上直接存值,傳值 = 複製值
  • 引用型別:棧上存引用 (指標),傳值 = 複製引用,雙方指向同一堆物件
  • Java 無傳址/傳引用,C++ 才有 void f(int& x) 真正傳引用

2. 逃逸分析與棧上分配

JVM 透過逃逸分析判斷物件不逃逸出方法/執行緒,可優化為:

  • 棧上分配:物件直接在棧幀分配,方法結束自動銷毀,零 GC 壓力
  • 標量替換:物件拆解為基本型別局部變數,完全消除物件分配
  • 同步消除:無逃逸物件的同步鎖直接移除

// 啟用逃逸分析 (JDK 8+ 預設開啟)
-XX:+DoEscapeAnalysis
-XX:+EliminateAllocations  // 標量替換
-XX:+EliminateLocks        // 同步消除

3. 字串常量池位置演進

  • JDK 6:永久代
  • JDK 7:移至堆 (方便 GC 回收)
  • JDK 8+:元空間 (類別元資料) + 堆 (字串常量)

常見誤區澄清

誤區事實
「基本型別都在棧上」基本型別作為物件欄位時在堆上;作為區域變數在棧上
「引用型別都在堆上」引用變數 (指標) 在棧上,指向的物件在堆上
「堆只存物件」陣列 (基本型別陣列/引用陣列) 也是物件,在堆上
「棧大小固定不會 OOM」棧過深遞歸會 StackOverflowError;大量線程總棧記憶體可耗盡
「新建物件必在堆」逃逸分析後可棧上分配/標量替換

效能調優實務

  1. 減少物件分配:複用物件、使用基本型別集合 (Trove、FastUtil)、逃逸分析友好寫法
  2. 調整堆大小:-Xms -Xmx 設相同值避免震盪,新生代佔 1/3~1/2
  3. 調整棧大小:遞歸深度大時增大 -Xss2m,但減少可建立線程數
  4. 啟用 TLAB:-XX:+UseTLAB (預設開) 線程本地分配緩衝,減少 CAS 競爭
  5. 監控指標:堆使用率、GC 頻率/耗時、線程棧深度、物件分配率
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved