簡介
內存模型描述了程序中各個變量(實例域、靜態域和數組元素)之間的關係,以及在實際計算機系統中將變量存儲到內存和從內存中取出變量這樣的底層細節,對象最終是存儲在內存裏面的,這點沒有錯,但是編譯器、運行庫、處理器或者系統緩存可以有特權在變量指定內存位置存儲或者取出變量的值。【
JMM
】(Java Memory Model
的縮寫)允許編譯器和緩存以數據在處理器特定的緩存(或寄存器)和主存之間移動的次序擁有重要的特權,除非程序員使用了volatile
或synchronized
明確請求了某些可見性的保證。
想要了解 JAVA 的內存模型,就得了解計算機的內存模型,計算機中並不存在 JVM 的概念,但是真實的數據讀寫操作又是在計算機中運行的。下面我們先來了解一下計算機的相關知識。
馮·諾伊曼體系
著名的馮·諾伊曼體系中把計算機劃分爲5個部分,分別是:
- 輸入設備
- 輸出設備
- 存儲器
- 運算器
- 控制器
存儲器又分爲:主存儲器和輔存儲器,運算器和控制器構成了計算機的CPU,主存儲器就是我們所說的內存,輔存儲器對應的是硬盤,這裏我們只要關係主存儲器。CPU與主存儲器之間的數據交換模型,就是神祕的計算機內存模型。
計算機內存模型
CPU和主存儲區的數據有一個過程,CPU要對主存儲器中的數據進行操作時,首先要獲取主存中的數據,會將主存儲中數據複製到CPU緩存區中,(一般都會存在多級緩存區),再將CPU緩存中的數據、指令保存到寄存器中,CPU 內核執行寄存器中的指令,而且運算完成之後並不是馬上更新到主存儲器中,而是再CPU覺得合適的時候更新數據到主存中。
但CPU中計算遵循了一個標準:線程級別結果正確。即當前線程的數據在寄存器,緩衝區,主存中的數據一致。多個線程可能不一致,這就是導致線程安全的原因,也是學習計算機內存的原因。
JAVA內存模型
稍微瞭解計算機的內存模型之後,我們再來看看Java的內存模型。
Java內存模型將JVM劃分爲兩個部分:
- 線程棧(Thread Stack)
- 堆(Heap)
那麼Java中的變量到底保存在哪呢?這是有明確規定的。
哪些保存在棧中
- 原始類型局部變量
- 引用類型局部變量的引用
哪些保存在堆中
- 引用類型局部變量的引用指向的對象
- 成員變量(原始類型,引用類型)
保存在棧中的變量是線程安全的,保存在堆中的變量是線程共享的,雖然引用類型局部變量的引用保存在棧中,但是其指向的對象保存在堆中,所以也會存在線程不安全。
分別學習了計算機內存模型和Java語言的內存模型之後,但我們還不知道Java內存模型怎麼在真實的計算機中運行的呢?
Java內存模型和計算機內存模型的交互
棧中數據可能保存在計算機的位置
- cpu寄存器
- cpu緩衝區
- 主內存
堆中數據可能保存在計算機的位置
- cpu寄存器
- cpu緩衝區
- 主內存
JVM Thread Stack和Heap中的數據可能在Computer內存中出現的位置有CPU 寄存器,CPU緩衝區,主內存。多線程執行時,數據存在可見性,一致性,原子性等問題。