jvm内存模型_四种视角看JVM内存模型
1.JVM運行視角
程序計數(shù)器
Java虛擬機棧
本地方法棧
Java堆
方法區(qū)
?
? ? ? ? 1?.程序計數(shù)器
? ? ??? 程序計數(shù)器是一塊較小的內(nèi)存空間,它可以看作是當(dāng)前線程所執(zhí)行的行號指示器。這個計數(shù)器記錄的是正在執(zhí)行的虛擬機字節(jié)碼指令的地址。此內(nèi)存區(qū)域是唯一一個在JAVA虛擬機規(guī)范中沒有規(guī)定任何OutOfMemoryError情況的區(qū)域。
? ? ? ? 2.Java虛擬機棧
? ? ? ??與程序計數(shù)器一樣,Java虛擬機棧也是線程私有的。Java虛擬機棧是描述Java方法運行過程的內(nèi)存模型。Java虛擬機棧會為每個方法在執(zhí)行的同時都會創(chuàng)建一個棧幀用于存儲局部變量(存放基本數(shù)據(jù)類型變量,引用類型的變量,返回類型的變量),操作數(shù)棧,動態(tài)鏈接,方法出口信息。
? ? ? ? 3.本地方法棧
? ? ? ??本地方法棧與虛擬機所發(fā)揮的作用是非常相似的(HotSpot虛擬機中,直接就把本地方法棧和虛擬機棧合二為一),它們的區(qū)別不過是虛擬機執(zhí)行Java方法服務(wù),而本地方法棧則為虛擬機使用到的Native方法服務(wù)。本地方法被執(zhí)行的時候,在本地方法棧也會創(chuàng)建一個幀棧,用于存放該本地方法的局部變量表、操作數(shù)棧,動作鏈接,出口信息。方法執(zhí)行完畢后相應(yīng)的棧幀也會出棧并釋放內(nèi)存空間。
? ? ? ?4.Java堆
? ? ???堆是用來存放內(nèi)存對象的,是Java虛擬機所管理的內(nèi)存中最大的一塊。所有的對象實例以及數(shù)組都要在堆上進(jìn)行分配。
? ? ? 5.方法區(qū)
? ? ???方法區(qū)育Java堆一樣,是一個線程共享的內(nèi)存區(qū)域。它用于存儲已被虛擬機加載的類信息,常量,靜態(tài)變量、即時編譯器后的代碼等數(shù)據(jù)。雖然Java虛擬機規(guī)范把方法區(qū)描述為難的一個邏輯部分,但是它卻有個別名叫做Non-Heap(非堆),目的是為了和Java堆區(qū)分開來。
? ? ? 6.直接內(nèi)存
? ? ??直接內(nèi)存并不是虛擬機運行時數(shù)據(jù)區(qū)的一部分,也不是Java虛擬機規(guī)范中定義的內(nèi)存區(qū)域。但是這部分內(nèi)存也被頻繁的使用。在JDK1.4中新加入了NIO(New Input/Output)類,引入了一種基于通道和緩沖的IO方式。它可以使用Native函數(shù)庫直接分配堆外內(nèi)存,然后通過一個存儲在Java堆中的DirectByteBuffer對象作為這塊內(nèi)存的引用進(jìn)行操作。這樣能在一些場景中顯著提高性能,因為避免了在Java堆和Native堆中來回復(fù)復(fù)制數(shù)據(jù)。直接內(nèi)存的大小不受Java虛擬機控制,但是當(dāng)本機物理內(nèi)存不足時就會拋出OutOfMemoryErrot錯誤。
圖二 線程共享與獨有的數(shù)據(jù)區(qū)
思考問題:為什么局部變量是線程安全的?答案見文末最后
2.JVM內(nèi)存功能視角
從JVM內(nèi)存可以分為三部分
Heap區(qū)(堆內(nèi)存)
非Heap(非堆內(nèi)存)
其他區(qū)
圖三JVM內(nèi)存功能分區(qū)
Heap區(qū):Eden Space(伊甸園),Survivor Space(幸存者區(qū)),Tenured Gen(老年代-養(yǎng)老區(qū))
非Heap區(qū):Code Cache(代碼緩沖區(qū)),Perm Gen(永久代),Java虛擬機棧,本地方法棧。
其他區(qū):直接內(nèi)存
3.線程運行視角
圖片四線程,工作內(nèi)存和主內(nèi)存之間的關(guān)系
Java內(nèi)存模型規(guī)定了所有的變量都要存儲在主內(nèi)存中,但是每個線程都有自己的工作內(nèi)存,線程的工作內(nèi)存保存了該線程使用的變量。這些變量實際上是主內(nèi)存的副本拷貝,線程對變量的所有操作都必須在工作內(nèi)存中進(jìn)行,而不是直接讀取主內(nèi)存的變量。】
思考問題:volatile變量?答案見最后
4.垃圾回收視角
JVM的垃圾回收主要針對的是堆內(nèi)存。在垃圾回收過程,堆內(nèi)存有以下特點:
堆內(nèi)存劃分為新生代和老年代兩部分,新生代主要用于存放新創(chuàng)建的對象與存活時長小的對象,老年代則用來存放存活時間長的對象
新生代又進(jìn)一步劃分為E,S1,S2三個區(qū),其中,E代表Eden區(qū);S1,S2則代表兩個類似的Survior。minorGC時候,Eden區(qū)不能被會回收的對象被放入到空的survior,Eden則肯定會被清空。另一個surivor里不能被GC回收的對象也會被放入這個surivor,始終保證一個surivor是空的
一個對象被minorGC回收了N次沒有被回收掉,則會被移除到老年區(qū)里(該次數(shù)通過設(shè)置-XX:InitialTenuringThresHold)
當(dāng)老年代的空間被耗盡了,則觸發(fā)FullGC
?問題解答:
1.為什么局部變量是線程安全的?
JVM在執(zhí)行Java程序時,會根據(jù)其數(shù)據(jù)用途把內(nèi)存劃分為若干數(shù)據(jù)區(qū)域,包括方法區(qū),堆,棧(JVM,本地方法棧),程序計數(shù)器,其中前兩者是所有線程共有的,后兩者是每個線程獨有的,因此,棧是線程私有的,一個線程一個棧,并且棧由棧幀組成,棧幀保存一個方法的局部變量表(包括參數(shù)和局部變量),操作數(shù)棧,常量池指針等,每一次方法的調(diào)用實際上是創(chuàng)建一個幀棧,并且壓棧。
所以方法調(diào)用實際是幀棧在入棧和出棧的操作,因為棧是線程私有的,所以每個棧之間是獨立的,所以幀棧對于多個線程棧來說不存在共享問題,也就不會存在線程安全的問題了
2.Volatile變量
根據(jù)JVM規(guī)范的規(guī)定,volatile變量依然有工作內(nèi)存的拷貝,但是由于它特殊的操作順序規(guī)定,所有看起來如同直接在主內(nèi)存中讀寫。
如果對申明了volatile的變量進(jìn)行寫操作,JVM就會向處理器發(fā)送一條Lock前綴的指令,將這個變量所在工作所在內(nèi)存的數(shù)據(jù)寫回到主內(nèi)存,但是,就算寫回到主內(nèi)存,如果其他線程工作內(nèi)存的值還是舊的,再執(zhí)行計算操作就會有問題,所以,在多處理器下為了保證各個處理器的緩存是一致的,就會實現(xiàn)緩存一致性協(xié)議,,每個處理器通過嗅探在總棧上傳播的數(shù)據(jù)來檢查自己緩存的值是不是過期了。當(dāng)處理器發(fā)現(xiàn)自己緩存行對應(yīng)的內(nèi)存地址被修改,就會將當(dāng)前處理器的緩存行設(shè)置成無效狀態(tài),當(dāng)處理器對這個數(shù)據(jù)進(jìn)行修改操作的時候,會重新從主內(nèi)存中把數(shù)據(jù)讀到處理器緩存中。
總結(jié)
以上是生活随笔為你收集整理的jvm内存模型_四种视角看JVM内存模型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: quick time不可用_那些校园中“
- 下一篇: 云海技术u盘怎么恢复成普通盘_BITLO