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

JVM 運行時記憶體分配機制深度解析:執行緒堆疊與主記憶體交互

     編輯:Java 相關知識

在《Java 垃圾回收整理》一文中,我們已概覽 JVM 運行時記憶體區域劃分。本文聚焦於 JVM 虛擬機棧(執行緒堆疊) 與 堆記憶體 之間的變數存取與同步機制,這是理解 Java 併發程式設計的基石。

核心概念:執行緒私有堆疊 vs 共享堆

  • 執行緒堆疊(Thread Stack):每條執行緒獨擁一份,存放區域變數、方法呼叫幀、運算中間結果。屬於執行緒私有記憶體,生命週期與執行緒同步。
  • 堆記憶體(Heap):所有執行緒共享,存放物件實例、陣列、靜態欄位。屬於主記憶體(Main Memory)範疇。

當執行緒需要存取物件欄位時,流程如下:

  1. 透過物件引用在堆中定位目標變數
  2. 將變數值 load(載入) 至執行緒本地工作記憶體(Local Memory),建立變數副本
  3. 執行緒僅操作副本,不再直接觸碰主記憶體
  4. 於某一時刻(如執行緒結束前、同步點)將副本值 store/write(寫回) 至主記憶體

下圖說明此交互流程:

執行緒工作記憶體與主記憶體交互示意圖

JMM 定義的八種原子操作

Java 記憶體模型(JMM)規範了主記憶體與工作記憶體交互的八種原子操作:

操作作用對象說明
read / load主記憶體 → 工作記憶體從主記憶體讀取變數值並載入工作記憶體
use / assign工作記憶體執行程式碼,修改工作記憶體中的變數副本(可多次出現)
store / write工作記憶體 → 主記憶體將工作記憶體資料刷新回主記憶體

非原子性帶來的可見性問題

上述操作並非不可分割的原子操作序列。若執行緒 1 執行 read/load 後,主記憶體變數被執行緒 2 修改,執行緒 1 的工作記憶體不會自動感知,導致運算結果與預期不符(典型的臟讀)。

volatile 的語義與侷限

volatile 關鍵字僅保證:

  • 可見性:read/load 時從主記憶體獲取最新值
  • 禁止指令重排:編譯器與 CPU 不會重排序 volatile 變數的讀寫操作

但 volatile 無法保證原子性。考慮 count++ 這類「讀取-修改-寫入」複合操作:

  1. 執行緒 1、2 同時 read/load 取得 count = 5
  2. 執行緒 1 遞增後 write 回主記憶體 → count = 6
  3. 執行緒 2 基於舊副本(5)遞增後 write → count = 6(預期應為 7)

結果:兩執行緒皆用 volatile 修飾,仍發生更新遺失。對於複合操作,必須使用 synchronized、Lock 或 AtomicInteger 等原子類別。

總結

  • 執行緒操作的是工作記憶體副本,非直接操作主記憶體
  • 八種交互操作非原子序列,多執行緒下易產生可見性與原子性問題
  • volatile 僅解決可見性與有序性,不解決原子性
  • 複合操作需顯式同步機制(synchronized/Lock/原子類別)

深入理解這套模型,是編寫正確、高效能 Java 併發程式的前提。

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