JVM的GC過程

既然創建的對象,在不使用後不會立馬清除,會在GC時才真正清除,那麼,

1.什麼時候觸發GC?

2.那一部分觸發GC?

3.如何進行回收?

首先,我們從對象存儲的部分看起,即堆內存。

我們代碼在JVM上一直不停的跑,此時就會在堆內存中創建對象,此處假設我們初始的參數配置如下:

-Xms20M -Xmx20M  -Xmn10M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256 -XX:SurvivorRatio=8 
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
 -Xloggc:gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/logs

配置詳情,請瀏覽最下方。

然後運行一下測試方法:

public class Test {
    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(30000);
        byte[] b=new byte[512*1024];
        for(int i=0;i<50;i++){
            Thread.sleep(1000);
            b=new byte[512*1024];
        }
    }
}

這裏,每次new一個0.5M的對象。

先想象一下,當這段代碼運行的時候,內存是如何變化的?

由上面配置,我們知道,新生代的內存大小是10M,默認Eden區:from:to的比例是:8:1:1

那麼eden區佔據了8M的內存,from和to各1M內存空間,啓動程序,使用jps查看運行的進程PID。

C:\Users\HBL>jps
8080
12036 RemoteMavenServer
14196 Launcher
16996 Test
9268 Jps

找到我們的Test的進程,然後執行:

jstat -gc 16996 1000 1000

此方法是每隔一秒鐘,更新出一條jstat統計語句,共打印1000次,當然程序結束也就不打印了。

這就是運行時實時查看內存變化。

這裏截取了第二次和第三次的gc,由於項目啓動會有一些配置對象,所以從第二次開始看

1.當上圖第一個GC發生的時候,此時Eden區由8M左右的大小,變爲0.5M,而s0由s1中的1M變爲0.5M,此時可能會發現老年代增加了大約0.5M的數據,這其實是配置對象,所以開始就省略了一次GC截圖。

2.當第二次發生GC後,Eden區又從8M左右變爲0.5M,而s1由s0的0.5M變爲0.5M,此時老年代沒有增加數據。

注:

這裏肯定存在一個疑問?

不是JVM默認15代後才進入老年代碼,那這裏爲什麼實際運行第二次GC就進入了?

這裏要注意,當>n代的對象內存大於s1或s0的內存一半的時候,就會將大於n的代的對象直接晉升老年代。

接着你會問,那麼爲什麼第一次都快1M了都沒進入老年?

因爲第一次GC的時候,即使大於一半也不會直接進入老年代,此處n必須大於1即上面的晉升條件,只是符合n>1的代數纔會晉升。

接着我們現在清楚看到了內存在GC後的變化,用圖展示如下:

要注意:

1.ParNew垃圾回收器使用的複製算法,同時它是多線程的。

2.ParNew垃圾回收器在執行過程中會造成STW,即它運行時,代碼是不能運行的。

那麼老年代如何進行垃圾回收,那就是ConcMarkSweep垃圾回收器,簡稱CMS垃圾回收器。

CMS的工作分四個步驟:

1)初始標記

此階段,標記出GC Root直接引用的對象,會造成STW,即停止程序運行。

2)併發標記

這個階段系統可以創建各種對象,繼續運行。對老年代所有對象進行GC Root追蹤。這個是最耗時的

3)重新標記

由於第二階段是並行運行,所以會有很多對象創建和對象變爲垃圾對象,所以此階段需要重新標記,它是STW的。

4)併發清理

此階段跟程序並行執行清理工作。

注:

併發標記和併發清理階段會有Concurrent Mode Failture錯誤發生,它是老年代在進行CMS回收時,創建的新對象內存放不下從而報的錯誤。默認92%進行CMS。

此時,CMS就會停止,轉爲serial old垃圾回收。

最後,看一下JVM配置:

jps:查看Java進程的PID,

jstat -gc PID:查看進程的虛擬機。

jstat -gc PID 1000 10:每隔一秒,更新出一條jstat統計語句,更新十次。

-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=5

每5次full gc觸發一次compaction,也就是壓縮

jmap -dump:live,format=b,file=文件名 [服務進程ID]:生成內存快照

-XX:+HeapDumpOnOutOfMemoryError:當內存發生oom自動dump一份內存快照出來

-XX:HeapDumpPath=內存快照存放的地址

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章