JVM8自適應導致內存居高不下


 

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

 


免責聲明!

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



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