(.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)]