Java內存模型(Java Memory Mode,JMM)
Java的內存模型指定了Java虛擬機如何與計算機的主存(RAM)進行工作,如上圖所示,理解Java內存模型對于編寫行為正確的并發程序是非常重要的。在JDK1.5以前的版本中,Java內存模型存在著一定的缺陷,在JDK1.5的時候,JDK官方對Java內存模型重新進行了修訂,在JDK1.8及最新的JDK版本都沿用了JDK1.5修訂的內存模型。
Java的內存模型決定了一個線程對共享變量的寫入何時對其他線程可見,Java內存模型定義了線程和主內存之間的抽象關系,具體如下:
- 共享變量存儲于主內存之中,每個線程都可以訪問。
- 每個線程都有私有的工作內存或者稱為本地內存。
- 工作內存只存儲該線程對共享變量的副本。
- 線程不能直接操作主內存,只有先操作本地內存之后才能寫入主內存。
-
工作內存和Java內存模型一樣也是一個抽象的概念,它其實并不存在,它涵蓋了緩存、寄存器、編譯器優化以及硬件等。
Java內存模型與CPU硬件架構交互圖
JVM內存模型
1、Class Loader(類加載器)就是將Class文件加載到內存,再說的詳細一點就是,把描述類的數據從Class文件加載到內存,并對數據進行校驗、轉換解析和初始化,最終形成可以被虛擬機直接使用的Java類型,這就是類加載器的作用。
2、Run Data Area(運行時數據區) 就是我們常說的JVM管理的內存了,也是我們這里主要討論的部分。運行數據區是整個JVM的重點。我們所有寫的程序都被加載到這里,之后才開始運行。這部分也是我們這里將要討論的重點。
數據 | 描述 |
---|---|
Program Counter Register(程序計數器) | 線程私有、指向下一條要很執行的指令 |
Java Stack(Java虛擬機棧) | 線程私有,生命周期與線程相同。描述的是Java方法執行的內存模型:每個方法被執行的時候都會同時創建一個棧幀(Stack Frame)用于存儲局部變量表、操作棧、動態鏈接、方法出口 |
Native Method Stack(本地方法棧) | 為虛擬機使用到的Native 方法服務 |
Heap(線程共享) | 所有的對象實例以及數組都要在堆上分配,是垃圾收集器管理的主要區域。由于現在收集器基本采用的分代收集算法,所以Java堆中還可以細分:新生代和老生代,更細致一點的有Eden空間、From Survivor空間、To Survivor空間等。 |
Method Area(方法區) | 被多個線程共享的內存區域,它主要用于存儲已經被虛擬機加載的類信息、常量、靜態變量、JIT編譯后的代碼等數據。 |
3、Execution engine(執行引擎) 是Java虛擬機最核心的組成部分之一。執行引擎用于執行指令,不同的java虛擬機內部實現中,執行引擎在執行Java代碼的時候可能有解釋執行(解釋器執行)和編譯執行(通過即時編譯器產生本地代碼執行,例如BEA JRockit),也有可能兩者兼備。任何JVM specification實現(JDK)的核心都是Execution engine,不同的JDK例如Sun 的JDK 和IBM的JDK好壞主要就取決于他們各自實現的Execution engine的好壞。
4、Native interface 與native libraries交互,是其它編程語言交互的接口。當調用native方法的時候,就進入了一個全新的并且不再受虛擬機限制的世界,所以也很容易出現JVM無法控制的native heap OutOfMemory。
JVM和JMM之間的關系
JMM中的主內存、工作內存與JVM中的Java堆、棧、方法區等并不是同一個層次的內存劃分,這兩者基本上是沒有關系的,如果兩者一定要勉強對應起來,那從變量、主內存、工作內存的定義來看,主內存主要對應于Java堆中的對象實例數據部分,而工作內存則對應于虛擬機棧中的部分區域。從更低層次上說,主內存就直接對應于物理硬件的內存,而為了獲取更好的運行速度,虛擬機(甚至是硬件系統本身的優化措施)可能會讓工作內存優先存儲于寄存器和高速緩存中,因為程序運行時主要訪問讀寫的是工作內存。