YOUNG GC
jvm年輕代分為eden區和survivor區,對象被創建后首先在eden區,如果一次young gc沒有將其回收的話,會到survivor區。從survivor區到old generation需要了解下動態年齡判斷
動態年齡判斷:
1.對象超過15次沒有被回收,可以通過MaxTenuringThreshold設置
2.相同年齡的對象超過survivor區的50%,可以通過TargetSurvivorRatio設置
對象超過15次沒有被回收不太可能,那就是survivor區太小了?我們通過命令 jmap -heap 進程號來查看堆信息
啟動程序時,只設置了初始堆內存和最大堆內存大小,其他都是默認參數。默認情況下,新生代和老年代的默認比例是1:2 ,eden區和兩個survivor區的默認比例是8:1:1
而上圖中我們可以看到年輕代與老年代的比例約等於 1:3 。eden區和兩個survivor區的比例為199:1:1,都100多倍了
AdaptiveSizePolicy
經過查詢發現JDK1.8的默認垃圾回收器是UseParallelGC ,默認啟動了AdaptiveSizePolicy。這個參數會讓垃圾回收器根據每次垃圾回收的GC時間和吞吐量來動態調整eden區和survivor區的比例。
AdaptiveSizePolicy有三個目標:
- Pause goal : 應用達到預期的GC暫停時間。
- Throughput goal : 應用達到預期的吞吐量,即應用正常運行時間/(正常運行時間+GC耗時)
- Minimum footprint :近可能小的內存占用量
AdaptiveSizePolicy為了達到三個預期目標,涉及以下操作:
- 如果GC停頓時間超過了預期值,會減小內存大小。理論上,減小內存,可以減少垃圾標記等操作的耗時,以此達到預期停頓時間。
- 如果應用吞吐量小於預期,會增加內存大小。理論上,增大內存,可以降低GC的頻率,以此達到預期吞吐量。
- 如果應用達到了前兩個目標,則嘗試減小內存,以減小內存消耗
AdaptiveSizePolicy 看上去很智能,但有時它也很調皮,會引發 GC 問題。
我們上圖中,eden區和兩個survivor區的比例都100多倍了,其原因就是AdaptiveSizePolicy為了達到期望的目標而進行了調整。
上圖中 Survior 區變小,老年代占比變高的原因分析如下
1.在默認 SurvivorRatio = 8 的情況下,沒有達到吞吐量的期望,AdaptiveSizePolicy 加大了 Eden 區的大小。From 和To 區被壓縮到只有 2M。
2.當 YGC 發生時候,由於 To 區太小,存活的對象直接進入到老年代。老年代占用量逐漸變大。
處理方案
方案一 : 關閉AdaptiveSizePolicy策略,同時顯式申明survivor區的比例。JVM增加參數
-XX:-UseAdaptiveSizePolicy -XX:SurvivorRatio=8
方案二 : 使用CMS垃圾回收器。CMS默認關閉AdaptiveSizePolicy。JVM配置參數
-XX:+UseConcMarkSweepGC
參考地址
堆內存居高不下,JDK8自適應作怪 https://www.jianshu.com/p/564017fe8a04
JVM GC 之 [AdaptiveSizePolicy] 實戰 https://www.jianshu.com/p/7414fd6862c5