jvm(1)---java內存結構


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)

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM