日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一个简单案例,带你看懂GC日志!

發布時間:2025/3/21 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一个简单案例,带你看懂GC日志! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

環境準備

這樣一個案例程序:

public?class?Main?{public?static?void?main(String[]?args)?{byte[]?array1?=?new?byte[4?*?1024?*?1024];array1?=?null;byte[]?array2?=?new?byte[2?*?1024?*?1024];byte[]?array3?=?new?byte[2?*?1024?*?1024];byte[]?array4?=?new?byte[2?*?1024?*?1024];byte[]?array5?=?new?byte[128?*?1024];byte[]?array6?=?new?byte[2?*?1024?*?1024];} }

我們采用如下參數來運行上述程序:

?

-XX:NewSize=10M -XX:MaxNewSize=10M -XX:InitialHeapSize=20M -XX:MaxHeapSize=20M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:PretenureSizeThreshold=3M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log

?

參數介紹:

-XX:NewSize:初始年輕代大小 -XX:MaxNewSize:最大年輕代大小 -XX:InitialHeapSize:定義堆的初始化大小,默認值是物理內存的1/64,其實就是:-Xms -XX:MaxHeapSize:定義最大堆的大小,默認為物理內存的1/4,其實就是:-Xmx -XX:SurvivorRatio:Eden區與Survivor區的大小比值 -XX:MaxTenuringThreshold:年輕代對象轉換為老年代對象最大年齡值 -XX:PretenureSizeThreshold=3M:對象大小超過3M時直接在老年代分配內存 -XX:+UseParNewGC:使用ParNew收集器 -XX:+UseConcMarkSweepGC:使用CMS收集器 -XX:+PrintGCDetails:GC時打印詳細信息 -Xloggc:輸出GC日志信息到文件中

打印的GC日志情況:

0.118:?[GC?(Allocation?Failure)?0.118:?[ParNew?(promotion?failed):?8143K->8713K(9216K),?0.0043061?secs]0.122:?[CMS:?8194K->6675K(10240K),?0.0038347?secs]?12239K->6675K(19456K),?[Metaspace:?3042K->3042K(1056768K)],?0.0082981?secs]?[Times:?user=0.03?sys=0.01,?real=0.01?secs]? Heappar?new?generation???total?9216K,?used?2213K?[0x00000007bec00000,?0x00000007bf600000,?0x00000007bf600000)eden?space?8192K,??27%?used?[0x00000007bec00000,?0x00000007bee297c8,?0x00000007bf400000)from?space?1024K,???0%?used?[0x00000007bf500000,?0x00000007bf500000,?0x00000007bf600000)to???space?1024K,???0%?used?[0x00000007bf400000,?0x00000007bf400000,?0x00000007bf500000)concurrent?mark-sweep?generation?total?10240K,?used?6675K?[0x00000007bf600000,?0x00000007c0000000,?0x00000007c0000000)Metaspace???????used?3063K,?capacity?4496K,?committed?4864K,?reserved?1056768Kclass?space????used?334K,?capacity?388K,?committed?512K,?reserved?1048576K

「日志詳解:」

GC:表明進行了一次垃圾回收,前面沒有Full修飾,表明這是一次Young GC

Allocation Failure:表明本次引起GC的原因是因為在年輕代中沒有足夠的空間能夠存儲新的數據了

ParNew:表明本次GC發生在年輕代并且使用的是ParNew垃圾收集器。ParNew是一個Serial收集器的多線程版本,會使用多個CPU和線程完成垃圾收集工作(默認使用的線程數和CPU數相同,可以使用-XX:ParallelGCThreads參數限制)

ParNew (promotion failed): 8143K->8713K(9216K) 8143K->8713K(9216K):單位是KB,三個參數分別為:GC前該內存區域(這里是年輕代)使用容量,GC后該內存區域使用容量,該內存區域總容量。

0.0043061 secs:該內存區域GC耗時,單位是秒

CMS: 8194K->6675K(10240K), 0.0038347 secs] 12239K->6675K(19456K)8194K->6675K(10240K):GC前該內存區域(這里是老年代)使用容量變化,10240K表示該內存區域總容量, 12239K->6675K(19456K):三個參數分別為:堆區垃圾回收前的大小,堆區垃圾回收后的大小,堆區總大小

Times: user=0.03 sys=0.01, real=0.01 secs:分別表示用戶態耗時,內核態耗時和總耗時

同時可以看到出現了promotion failed,那什么情況下會出現promotion failed?

推薦閱讀:46張PPT弄懂JVM、GC算法和性能調優

?

在進行Young GC時,Survivor Space放不下,對象只能放入老年代,而此時老年代也放不下時會出現

?

詳細介紹

「接下來詳細介紹GC過程:」

首先我們看如下代碼:

byte[]?array1?=?new?byte[4?*?1024?*?1024]; array1?=?null;

這行代碼直接分配了一個4MB的大對象,此時這個對象會直接進入老年代,接著array1不再引用這個對象

接著看下面的代碼:

byte[]?array2?=?new?byte[2?*?1024?*?1024]; byte[]?array3?=?new?byte[2?*?1024?*?1024]; byte[]?array4?=?new?byte[2?*?1024?*?1024]; byte[]?array5?=?new?byte[128?*?1024];

連續分配了4個數組,其中3個是2MB的數組,1個是128KB的數組,如下圖所示,全部會進入Eden區域中

接著會執行如下代碼:

byte[]?array6?=?new?byte[2?*?1024?*?1024];

此時還能放得下2MB的對象嗎?不可能了,因為Eden區已經放不下了。因此此時會直接觸發一次Young GC。

我們看下面的GC日志:

?

ParNew (promotion failed): 8143K->8713K(9216K), 0.0043061 secs

?

這行日志顯示了,Eden區原來是有8000多KB的對象,但是回收之后發現一個都回收不掉,因為上述幾個數組都被變量引用了一,所以一定會直接把這些存活的對象放入到老年代里去,但是此時老年代里已經有一個4MB的數組了,還能放的下3個2MB的數組和1個128KB的數組嗎?

明顯是不行的,此時一定會超過老年代的10MB大小。

所以此時我們看cms的gc日志:

?

CMS: 8194K->6675K(10240K), 0.0038347 secs] 12239K->6675K(19456K), [Metaspace: 3042K->3042K(1056768K)], 0.0082981 secs

?

大家可以清晰看到,此時執行了CMS垃圾回收器的Full GC,我們知道Full GC其實就是會對老年代進行Old GC, 同時一般會跟一次Young GC關聯,還會觸發一次元數據區(永久代)的GC。

在CMS Full GC之前,就已經觸發過Young GC了,此時大家可以看到此時Young GC就已經有了,接著就是執行針對 老年代的Old GC,也就是如下日志:

?

CMS: 8194K->6675K(10240K), 0.0038347 secs]

?

「這里看到老年代從8MB左右的對象占用,變成了6MB左右的對象占用,這是怎么個過程呢?」

很簡單,一定是在Young GC之后,先把2個2MB的數組放入了老年代,此時要繼續放1個2MB的數組和1個128KB的數組到老年代,一定會放不下,所以此時就會觸發CMS的Full GC

然后此時就會回收掉其中的一個4MB的數組,因為他已經沒人引用了

接著放入進去1個2MB的數組和1個128KB的數組

所以大家再看CMS的垃圾回收日志:CMS: 8194K->6836K(10240K), 0.0049920 secs,他是從回收前的8MB變成了 6MB

最后在CMS Full GC執行完畢之后,其實年輕代的對象都進入了老年代,此時最后一行代碼要在年輕代分配2MB的數組就可以成功了

補充知識

為了方便理解上述內容,補充以下知識

「Young GC觸發條件:」

當年輕代Eden區域滿的時候會觸發一次Young GC

「Full GC觸發條件:」

Full GC用于清理整個堆空間。它的觸發條件主要有以下幾種:

1.顯式調用System.gc方法(建議JVM觸發)。

2.元空間不足

3.年代空間不足,引起Full GC。這種情況比較復雜,有以下幾種:

  • 大對象直接進入老年代引起,由-XX:PretenureSizeThreshold參數定義

  • Young GC時,經歷過多次Young GC仍存在的對象進入老年代。

  • Young GC時,動態對象年齡判定機制會將對象提前轉移老年代。年齡從小到大進行累加,當加入某個年齡段后,累加和超過survivor區域-XX:TargetSurvivorRatio的時候,從這個年齡段往上的年齡的對象進入老年代

  • Young GC時,Eden和From Space區向To Space區復制時,大于To Space區可用內存,會直接把對象轉移到老年代

4.JVM的空間分配擔保機制可能會觸發Full GC:

空間擔保分配是指在發生Young GC之前,虛擬機會檢查老年代最大可用的連續空間是否大于新生代所有對象的總空間。

推薦閱讀:46張PPT弄懂JVM、GC算法和性能調優

如果大于,則此次Young GC是安全的。

如果小于,則虛擬機會查看HandlePromotionFailure設置值是否允許擔保失敗。

如果HandlePromotionFailure=true,那么會繼續檢查老年代最大可用連續空間是否大于歷次晉升到老年代的對象的平均大小,如果大于,則嘗試進行一次Young GC,但這次Young GC依然是有風險的,失敗后會重新發起一次Full gc;如果小于或者HandlePromotionFailure=false,則改為直接進行一次Full GC。

「GC Easy工具」

這里推薦一個gceasy(https://gceasy.io)工具,可以上傳gc文件,然后他會利用可視化的界面來展現GC情況

如果覺得不錯,點個贊,轉發下再走吧,謝謝

參考:

https://www.oracle.com/java/technologies/javase/vmoptions-jsp.html

總結

以上是生活随笔為你收集整理的一个简单案例,带你看懂GC日志!的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。