別再混淆了!JVM內(nèi)存模型和Java內(nèi)存模型的本質(zhì)區(qū)別
JVM 內(nèi)存模型(JVM Memory Model)和 Java 內(nèi)存模型(Java Memory Model, JMM)是 Java 開發(fā)中兩個非常重要的概念,但這兩個概念很容易被搞混,所以本文就來通俗易懂的講講二者的區(qū)別。
首先,我們先來看看各自的概念,以及其解決的問題。
1.JVM內(nèi)存模型
- 定位:JVM 在運行 Java 程序時對物理內(nèi)存的具體劃分和管理方式,用來保證 Java 程序正常執(zhí)行的。
- 目的:定義 Java 程序在運行時如何分配、使用和回收內(nèi)存。
- 核心組成:
a.堆(Heap):存儲對象實例(所有線程共享)。
b.方法區(qū)(Method Area):存儲類信息、常量等(JDK8 后由元空間實現(xiàn))。
c.虛擬機棧(VM Stack):存儲方法的局部變量、操作數(shù)棧(每個線程私有)。
d.本地方法棧(Native Method Stack):服務(wù)于 JVM 調(diào)用本地方法。
e.程序計數(shù)器(Program Counter Register):記錄線程當前執(zhí)行的指令地址。
- 關(guān)注點:內(nèi)存的分配、垃圾回收(GC)、內(nèi)存泄漏等問題。
JVM不劃分5大內(nèi)存區(qū)域行不行?
從理論上來講可能是可行的,但從程序的運行效率、垃圾回收的效率等方面來講不劃分內(nèi)存區(qū)域,所有的信息放到一起,其效率是非常慢的,是不能被允許的。
并且不劃分區(qū)域可能會導(dǎo)致關(guān)鍵數(shù)據(jù)易被污染的問題,例如方法區(qū)存儲的類元數(shù)據(jù)(如類結(jié)構(gòu)、靜態(tài)變量)需要長期存在且全局共享,若與臨時變量混存,可能導(dǎo)致類信息被意外覆蓋。例如,在熱加載類時,新類元數(shù)據(jù)可能覆蓋正在被其他線程使用的舊版本,引發(fā)不可預(yù)知的錯誤。
所以綜合來看,JVM 必須按存儲的數(shù)據(jù)類型劃分為不同的數(shù)據(jù)區(qū)域,以提升程序的執(zhí)行和垃圾回收的效率,并且可以減少程序在運行時的一些不必要的問題,這就是 JVM 內(nèi)存模型所解決的問題。
2.Java內(nèi)存模型
- 定位:Java 語言規(guī)范(JLS)定義的多線程環(huán)境下內(nèi)存訪問的規(guī)則和約束的一種規(guī)范。
- 目的:解決多線程并發(fā)時的內(nèi)存可見性、原子性、有序性問題,確保線程間正確通信。
- 核心概念:
a.主內(nèi)存(Main Memory):所有線程共享的內(nèi)存區(qū)域。
b.工作內(nèi)存(Working Memory):每個線程私有的內(nèi)存副本(可能對應(yīng) CPU 寄存器或緩存)。
c.happens-before原則:定義操作之間的偏序關(guān)系,確保可見性。
d.內(nèi)存屏障(Memory Barriers):禁止指令重排序的機制。
- 關(guān)注點:如何通過 synchronized、volatile 等關(guān)鍵字或并發(fā)工具類保證線程安全。
- 示例場景:解決多線程下共享變量的不可見性(如使用 volatile 禁止指令重排序)。
PS:也就是說“Java 內(nèi)存模型”主要是保證 Java 在多線程下正常運行的一種機制(或規(guī)定)。
小結(jié)
JVM內(nèi)存模型 | Java內(nèi)存模型(JMM) | |
范疇 | JVM 實現(xiàn)層面的內(nèi)存區(qū)域劃分 | 多線程并發(fā)編程的內(nèi)存訪問規(guī)則 |
主要目標 | 內(nèi)存分配、回收和管理 | 解決線程間的可見性、有序性和原子性問題 |
具體實現(xiàn) | 堆、棧、方法區(qū)等物理內(nèi)存劃分 | volatile、synchronized 等語義 |