一個程序運行時JVM的內(nèi)存分配

(.class字節(jié)碼)類加載到內(nèi)存之后,內(nèi)存模型:(ps:.class文件可以通過javap 指令反編譯成一個可讀文件)

[圖片上傳失敗...(image-516e29-1576910740725)]

首先介紹每個線程私有的java棧,本地方法棧,程序計數(shù)器

看如下程序:

[圖片上傳失敗...(image-80da98-1576910740725)]

以該程序為例,運行該程序,jvm會分配給該程序一個線程,總體圖示如下:

[圖片上傳失敗...(image-2f1acd-1576910740725)]

該線程在運行時候,java虛擬機會分配給該線程獨立的java棧,而棧幀存在于棧中,存放的是 每一個方法運行時候需要的數(shù)據(jù)(每一個方法都有一個棧幀,棧幀存的是 局部變量表,操作數(shù)棧,動態(tài)鏈接,方法出口),上圖有兩個方法,即 jvm會分配兩個棧幀。

首先入棧的是main方法的棧幀,當(dāng)main方法new一個math對象時候,該棧幀當(dāng)中存放了math的引用,而math對象是放在堆中,方法區(qū)中會放置Math類的.class文件,一些類的靜態(tài)變量和常量也會放入方法區(qū),比如:

[圖片上傳失敗...(image-edec27-1576910740725)]

然后main方法中調(diào)用了math方法(new了一個math對象),從而math方法的棧幀入棧,當(dāng)math方法執(zhí)行完畢之后,它的棧幀會彈出棧。

[圖片上傳失敗...(image-22bb47-1576910740725)]

(使用javap指令反編譯一下 Math.class)

[圖片上傳失敗...(image-7087fa-1576910740725)]

查詢jvm指令可知:iconst_1的含義是 [圖片上傳失敗...(image-ca366a-1576910740725)]

(棧即使 操作數(shù)棧),istore_1的含義是 [圖片上傳失敗...(image-973ff0-1576910740725)]

iconst_2,istore_2也一樣。對應(yīng) int a=1 ;int b=2;

[圖片上傳失敗...(image-5a4b83-1576910740725)]

程序計數(shù)器也是每一個線程私有的,每個方法運行的時候,都有一個程序計數(shù)器,作用是告訴jvm接下來該運行哪一行代碼,即是一個指針,如反編譯后圖的0,1,2,3......前四行代碼都執(zhí)行了,現(xiàn)在該運行4, 程序計數(shù)器放的內(nèi)容是4

[圖片上傳失敗...(image-1144fd-1576910740724)] [圖片上傳失敗...(image-37751-1576910740724)] [圖片上傳失敗...(image-e3bd6a-1576910740724)]

然后,執(zhí)行int c=(a+b)*10,對應(yīng) iload_1,iload_2 ,含義如下[圖片上傳失敗...(image-1e47f0-1576910740724)]

,對應(yīng)結(jié)果(從局部變量表 裝載到 操作數(shù)棧,PS:局部變量表中的值還在,只是復(fù)制到操作數(shù)棧中,下圖顯示不正確)

[圖片上傳失敗...(image-944b51-1576910740724)]

接著計算a+b,對應(yīng)的是將b=2,a=1都彈出棧,進行+運算,然后將算出的結(jié)果3,放入操作數(shù)棧中,然后需要10,所以將10也壓入棧

[圖片上傳失敗...(image-d2416f-1576910740724)]

執(zhí)行3*10的操作,需要將3和10均彈出棧進行乘的計算,計算的出30,再壓回操作數(shù)棧中,然后將30彈出棧,進入局部變量表:

[圖片上傳失敗...(image-b53101-1576910740723)] [圖片上傳失敗...(image-986ec5-1576910740724)]

[圖片上傳失敗...(image-a66dbd-1576910740724)]

最后math方法執(zhí)行方法執(zhí)行完畢,會通過方法出口返回給main方法,并且,math方法的棧幀主動彈出棧銷毀

[圖片上傳失敗...(image-b5b831-1576910740724)]

本地方法棧是存放程序調(diào)用的native方法,(或者程序底層的native方法)

[圖片上傳失敗...(image-a45c43-1576910740724)]

有個結(jié)論:java棧,本地方法棧,程序計數(shù)器是每一個線程私有的,而堆和方法區(qū)是所有線程所共享的。(堆和方法區(qū)共享是因為,其他線程也能創(chuàng)建相同的對象,比如math,也要用到方法區(qū)的一些內(nèi)容)

[圖片上傳失敗...(image-cec733-1576910740724)]

[圖片上傳失敗...(image-84548f-1576910740724)]

[圖片上傳失敗...(image-b53513-1576910740724)]

堆和方法區(qū)的介紹

[圖片上傳失敗...(image-824ff4-1576910740724)]

包括 新生代,老年代,元空間(MetaData space),(ps:方法區(qū)實際上不存在,只是一個邏輯上的概念,而元空間或者永久代<jdk 1.8之前>是方法區(qū)的具體代碼實現(xiàn))

老年代是新生代空間的兩倍。

當(dāng)程序創(chuàng)建對象的時候,對象會首先進入新生代的Eden中,如果新生代的Eden空間滿了,Jvm會進行一些小GC,將一些沒有引用指向的對象,即垃圾對象清除掉。其他的不能GC的對象(即還有引用指向的對象)會被移到Suvivor區(qū)域,如果第一個Suvivor區(qū)(From)也滿了,也會進行GC,GC之后,會將第一個Suvivor剩下的所有對象復(fù)制到第二個Suvivor區(qū)域(To)。

程序如果繼續(xù)創(chuàng)建對象,會繼續(xù)對Eden GC,這時候,其他不能GC的對象會被移到Survivor第二個區(qū)域中(To區(qū)域),第二個區(qū)域和第一個區(qū)域角色互換,重復(fù)上面操作,然后再一輪角色又互換。這樣經(jīng)過好幾輪.........................................

如果JVM這樣好幾次操作(JDK1.8默認15次,也可設(shè)置)之后,還有些對象沒有被GC,這些對象會被放入老年代Old Generation。如果程序再創(chuàng)建對象,新生代和老年代都滿了,JVM會對老年代進行一次full GC,清楚無效的對象,F(xiàn)ull GC可能會使JVM暫停(對用戶而言程序失去響應(yīng),但是內(nèi)部還是再做GC),而JVM調(diào)優(yōu)帶到的效果是:無非是使Full gc少執(zhí)行,而小GC也少執(zhí)行。

[圖片上傳失敗...(image-a14415-1576910740724)]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容