深入JAVA虛擬機_結(jié)構(gòu)


layout: post

title: 深入JAVA虛擬機_結(jié)構(gòu)

categories: JVM JAVA

description: 深入JAVA虛擬機_結(jié)構(gòu)

keywords: JVM JAVA


線程計數(shù)器

較小的內(nèi)存區(qū)塊,用於記錄當前綫程的字節(jié)碼執(zhí)行到了第幾行,字節(jié)碼解釋器通過計數(shù)器獲取下一條指令,每個程序計數(shù)器用來記錄一個綫程的
行號,所以它是綫程私有的

如果計數(shù)器執(zhí)行的是JAVA方法,則計數(shù)器記錄的是執(zhí)行的虛擬機字節(jié)碼指令地址。
如果計數(shù)器執(zhí)行的是一個本地方法,則計數(shù)器為Undefined

由於程序計數(shù)器只記錄當前指令地址嗎,所以不存在內(nèi)存溢出的情況,所以程序計數(shù)器也是所有jvm內(nèi)存區(qū)域中唯一一個沒有定義>OutOfMemoryError的區(qū)域。

虛擬機棧

綫程私有

一個線程一個棧,一個方法一個棧幀

虛擬機棧表示Java方法執(zhí)行的內(nèi)存模型,每調(diào)用一個方法就會為每個方法生成一個棧幀(Stack Frame),用來存儲局部變量表、操作數(shù)棧、動
態(tài)鏈接、方法出口等信息

虛擬機棧是一個后入先出的棧。棧幀是保存在虛擬機棧中的,棧幀是用來存儲數(shù)據(jù)和存儲部分過程結(jié)果的數(shù)據(jù)結(jié)構(gòu),同時也被用來處理動態(tài)鏈接Dynamic Linking、方法返回值和異常分派(Dispatch Exception)。線程運行過程中,只有一個棧幀是處于活躍狀態(tài),稱為“當前活躍棧幀”,當前活動棧幀始終是虛擬機棧的棧頂元素。

動態(tài)連接: 每個棧幀都包含一個指向運行時常量池中該棧幀所屬性方法的引用,持有這個引用是為了支持方法調(diào)用過程中的動態(tài)連接。在Class文件的常量池中存有大量的符號引用,字節(jié)碼中的方法調(diào)用指令就以常量池中指向方法的符號引用為參數(shù)。這些符號引用一部分會在類加載階段或第一次使用的時候轉(zhuǎn)化為直接引用,這種轉(zhuǎn)化稱為靜態(tài)解析。另外一部分將在每一次的運行期期間轉(zhuǎn)化為直接引用,這部分稱為動態(tài)連接。

堆區(qū)

綫程共享

新生代 老年代


新生代 老年代

年輕代(Young Generation)

對象在被創(chuàng)建時,內(nèi)存首先是在年輕代進行分配(注意,大對象可以直接在老年代分配)。當年輕代需要回收時會觸發(fā)>Minor GC(也稱作Young GC)。

年輕代由Eden Space和兩塊相同大小的Survivor Space(又稱S0和S1)構(gòu)成,可通過-Xmn參數(shù)來調(diào)整新生代大小,也可.
通過-XX:SurvivorRadio來調(diào)整Eden Space和Survivor Space大小。不同的GC方式會按不同的方式來按此值劃分Eden >Space和Survivor Space,有些GC方式還會根據(jù)運行狀況來動態(tài)調(diào)整Eden、S0、S1的大小。

年輕代的Eden區(qū)內(nèi)存是連續(xù)的,所以其分配會非常快;同樣Eden區(qū)的回收也非常快(因為大部分情況下Eden區(qū)對象存活>時間非常短,而Eden區(qū)采用的復(fù)制回收算法,此算法在存活對象比例很少的情況下非常高效,后面會詳細介紹)。

如果在執(zhí)行垃圾回收之后,仍沒有足夠的內(nèi)存分配,也不能再擴展,將會拋出OutOfMemoryError:Java Heap Space異
常。

老年代(Old Generation)

1.老年代用于存放在年輕代中經(jīng)多次垃圾回收仍然存活的對象
2.存放大對象,可以通過啟動參數(shù)設(shè)置->XX:PretenureSizeThreshold=2048,表示超過多大時就不在年輕代分配,而是
直接在老年代分配。此參數(shù)在年輕代采用Parallel Scavenge GC時無效,因為其會根據(jù)運行情況自己決定什么對象直接在
老年代上分配內(nèi)存;
3.存放大的數(shù)組對象,且數(shù)組對象中無引用外部對象。

當老年代滿了的時候就需要對老年代進行垃圾回收,老年代的垃圾回收稱作Major GC(也稱作Full GC)。

老年代所占用的內(nèi)存大小為-Xmx對應(yīng)的值減去-Xmn對應(yīng)的值。

本地方法棧

為線程私有。線程在調(diào)用本地方法時,來存儲本地方法的局部變量表,本地方法的操作數(shù)棧等等信息。

該方法的實現(xiàn)由非java語言實現(xiàn),比如C語言實現(xiàn)。你可以告知JVM編譯器去調(diào)用一個C語言編寫的方法。java作為高級編程語言,當對一些底層的代碼實現(xiàn),java實現(xiàn)起來難度大,編程效率也很低下。本地方法就很好的解決了這個問題


本地方法實現(xiàn)流程

該線程首先調(diào)用了兩個Java方法,而第二個Java方法又調(diào)用了一個本地方法,這樣導致虛擬機使用了一個本地方法棧。圖中的本地方法棧顯示為 一個連續(xù)的內(nèi)存空間。假設(shè)這是一個C語言棧,期間有兩個C函數(shù),他們都以包圍在虛線中的灰色塊表示。第一個C函數(shù)被第二個Java方法當做本地方法調(diào)用, 而這個C函數(shù)又調(diào)用了第二個C函數(shù)。之后第二個C函數(shù)被第二個Java方法當做本地方法調(diào)用,而這個C函數(shù)又調(diào)用了第二個C函數(shù)。之后第二個C函數(shù)又通過 本地方法接口回調(diào)了一個Java方法(第三個Java方法)。最終這個Java方法又調(diào)用了一個Java方法(他成為圖中的當前方法)

方法區(qū)

綫程共享
主要存放已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù),eg: spring 使用IOC或者AOP創(chuàng)建bean時,或者使用cglib,反射的形式動態(tài)生成class信息等

異常
當方法區(qū)無法滿足內(nèi)存分配需求時,將拋出OutOfMemoryError。
運行時常量池溢出:比如一直往常量池加入數(shù)據(jù),就會引起OutOfMemoryError異常。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容