jvm主要由三個子系統構成:類加載子系統,運行時數據區,執行引擎
運行時數據區主要包括:
1.本地方法棧:登記native方法,執行時加載本地方法庫
2.程序計數器:就是一個指針,用來存儲指向下一條執行指令的地址,也就是即將要執行的指令代碼,是一個非常小得空間,可以忽略不計。
3.java棧:java線程執行方法的內存模型,一個線程對應一個棧,每個方法在執行時都會創建一個棧幀,用於存儲局部變量表(引用),操作數棧,動態鏈接,方法出口等信息,不存在垃圾回收問題,生命周期和線程一致,線程結束該棧就釋放。可以通過-Xss來設置棧空間。
4.方法區:類的所有字段和方法字節碼,以及一些特殊的方法,構造函數,接口定義,所有定義的方法的信息都存放在這。此外還包括靜態變量,常量,運行時常量池
5.java堆:虛擬機啟動時創建,用於存放對象實例,幾乎所有的對象都在堆上面分配內存,當對象無法在該空間申請到內存就會拋出OutMemoryError異常,同時也是垃圾回收器主要管理的區域,可以通過-Xmx/Xms來設置最大/最小堆
其中1.2.3都是線程私有,4.5線程共享
線程私有java棧圖解:
java堆詳解:
新生代:類誕生、成長、消亡的區域,一個類在這里產生,應用,最后被垃圾回收器收集,結束生命。
新生代分為兩部分: 伊甸園區(Eden space:亞當,夏娃造人,這名字取得還是很有意義的)和幸存者區(Survivor pace) ,所有的類都是在伊甸園被new出來的。幸存區有兩個: 0區(Survivor 0 space(From))和1區(Survivor 1 space(To))。當伊甸園的空間用完時,程序又需要創建對象,JVM的垃圾回收器將對伊甸園區進行垃圾回收(Minor GC),將伊甸園區中的不再被其他對象所引用的對象進行銷毀。然后將伊甸園中的剩余對象移動到幸存From。若幸From也滿了,再對該區進行垃圾回收,然后移動到To。From到To操作一次,還存在To中的對象就相當於長了一歲,默認是15歲,如果到了15歲都還存在有引用,那么就放入老年代,可以用過-XX:MaxTenuringThreshold來設置這個年齡
老年代:新生代經過多次GC仍然存活的對象移動到老年區。若老年區也滿了,那么這個時候將產生FullGC,進行老年區的內存清理。若老年區執行了Full GC之后發現依然無法進行對象的保存,就會產生OOM異常“OutOfMemoryError”。可以同過減少FullGC來提高jvm性能
永久代(元數據):jdk1.8元數據區取代了永久代,本質和永久代類似,都是對JVM規范中方法區的實現,區別在於元數據區並不在虛擬機中,而是使用本地物理內存,永久代在虛擬機中,永久代邏輯結構上屬於堆,但是物理上不屬於堆,堆大小=新生代+老年代。元數據區也有可能發生OutOfMemory異常。
Jdk1.6及之前: 有永久代, 常量池在方法區
Jdk1.7:有永久代,但已經逐步“去永久代”,常量池在堆
Jdk1.8及之后: 無永久代,常量池在元空間
元數據區的動態擴展,默認–XX:MetaspaceSize值為21MB的高水位線。一旦觸及則Full GC將被觸發並卸載沒有用的類(類對應的類加載器不再存活),然后高水位線將會重置。新的高水位線的值取決於GC后釋放的元空間。如果釋放的空間少,這個高水位線則上升。如果釋放空間過多,則高水位線下降。
使用-XX:+PrintGCDetails參數打印GC日志,運行下面代碼:
package jvm; /** * @author: create by nijunyang * @date:2019/6/19 */ public class Test { public static void main(String[] args) { byte[] bytes1 = new byte[62000*1024]; byte[] bytes2 = new byte[10240*1024]; byte[] bytes3 = new byte[30000*1024]; // byte[] bytes4 = new byte[28000*1024]; // byte[] bytes5 = new byte[10240*1024]; } }
可以看到伊甸園區只有65536K,byte1->62000K 大對象被直接移入了老年代,因為 Survivor區大小無法存放該對象,所以在yong gc的時候直接將該對象放入老年代,
我們也可以通過設置-XX:PretenureSizeThreshold= 60000,使得創建大於60000字節的對象直接放入老年代。但是該參數只在Serial 和ParNew兩個垃圾收集器下面生效
byte2,byte3依然在伊甸園
放開bytes4之后會發現From區也有占用了99%,差不多就是bytes2的大小,說明bytes2移入了From,byte3也移入了老年代(byte1+byte3 = 92000K)