MaxTenuringThreshold 和 TargetSurvivorRatio參數說明


 

-XX:MaxTenuringThreshold
  晉升年齡最大閾值,默認15。在新生代中對象存活次數(經過YGC的次數)后仍然存活,就會晉升到老年代。每經過一次YGC,年齡加1,當survivor區的對象年齡達到TenuringThreshold時,表示該對象是長存活對象,就會直接晉升到老年代。

-XX:TargetSurvivorRatio
  設定survivor區的目標使用率。默認50,即survivor區對象目標使用率為50%。

  JVM會將每個對象的年齡信息、各個年齡段對象的總大小記錄在“age table”表中。基於“age table”、survivor區大小、survivor區目標使用率(-XX:TargetSurvivorRatio)、晉升年齡閾值(-XX:MaxTenuringThreshold),JVM會動態的計算tenuring threshold的值。一旦對象年齡達到了tenuring threshold就會晉升到老年代。

  為什么要動態的計算tenuring threshold的值呢?假設有很多年齡還未達到TenuringThreshold的對象依舊停留在survivor區,這樣不利於新對象從eden晉升到survivor。因此設置survivor區的目標使用率,當使用率達到時重新調整TenuringThreshold值,讓對象盡早的去old區。

  如果希望跟蹤每次新生代GC后,survivor區中對象的年齡分布,可在啟動參數上增加-XX:+PrintTenuringDistribution。

用法: -XX:MaxTenuringThreshold=3
該參數主要是控制新生代需要經歷多少次GC晉升到老年代中的最大閾值。在JVM中用4個bit存儲(放在對象頭中),所以其最大值是15。
但並非意味着,對象必須要經歷15次YGC才會晉升到老年代中。例如,當survivor區空間不夠時,便會提前進入到老年代中,但這個次數一定不大於設置的最大閾值

那么JVM到底是如何來計算S區對象晉升到Old區的呢?
首先介紹另一個重要的JVM參數:
-XX:TargetSurvivorRatio:一個計算期望s區存活大小(Desired survivor size)的參數。默認值為50,即50%。
當一個S區中所有的age對象的大小如果大於等於Desired survivor size,則重新計算threshold,以age和MaxTenuringThreshold兩者的最小值為准。

以一個Demo為例:

//-Xmx200M -Xmn50m -XX:TargetSurvivorRatio=60 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:MaxTenuringThreshold=3 //最小堆為50M,默認SurvivorRatio為8,那么可以知道Eden區為40M,S0和S1為5M public class App { public static void main(String[] args) throws InterruptedException { // main方法作為主線程,變量不會被回收 byte[] byte1 = new byte[1 * 1024 * 1024]; byte[] byte2 = new byte[1 * 1024 * 1024]; YGC(40); Thread.sleep(3000); YGC(40); Thread.sleep(3000); YGC(40); Thread.sleep(3000); // 這次再ygc時, 由於byte1和byte2的年齡經過3次ygc后已經達到3(-XX:MaxTenuringThreshold=3), 所以會晉升到old YGC(40); // ygc后, s0(from)/s1(to)的空間為0 Thread.sleep(3000); // 達到TargetSurvivorRatio這個比例指定的值,即 5M(S區)*60%(TargetSurvivorRatio)=3M(Desired survivor size) byte[] byte4 = new byte[1 * 1024 * 1024]; byte[] byte5 = new byte[1 * 1024 * 1024]; byte[] byte6 = new byte[1 * 1024 * 1024]; // 這次ygc時, 由於s區已經占用達到了60%(-XX:TargetSurvivorRatio=60), // 所以會重新計算對象晉升的min(age, MaxTenuringThreshold) = 1 YGC(40); Thread.sleep(3000); // 由於前一次ygc時算出age=1, 所以這一次再ygc時, byte4, byte5, byte6就要晉升到Old, // 而不需要等MaxTenuringThreshold這么多次, 此次ygc后, s0(from)/s1(to)的空間再次為0, 對象全部晉升到old YGC(40); Thread.sleep(3000); System.out.println("GC end!"); } //塞滿Eden區,局部變量會被回收,作為觸發GC的小工具 private static void YGC(int edenSize){ for (int i = 0 ; i < edenSize ; i ++) { byte[] byte1m = new byte[1 * 1024 * 1024]; } } } 

可以看到結果

//第一次YGC 2017-07-22T17:43:50.615-0800: [GC (Allocation Failure) 2017-07-22T17:43:50.615-0800: [ParNew: 39936K->2812K(46080K), 0.0126581 secs] 39936K->2812K(125952K), 0.0127387 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] //第二次YGC 2017-07-22T17:43:53.653-0800: [GC (Allocation Failure) 2017-07-22T17:43:53.653-0800: [ParNew: 43542K->2805K(46080K), 0.0144079 secs] 43542K->2805K(125952K), 0.0144607 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] //第三次YGC 2017-07-22T17:43:56.679-0800: [GC (Allocation Failure) 2017-07-22T17:43:56.679-0800: [ParNew: 43329K->2877K(46080K), 0.0010447 secs] 43329K->2877K(125952K), 0.0010784 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] //三次YGC后,此時age達到MaxTenuringThreshold閾值3,再次YGC時,會晉升到Old區,可以看到此時新生代空間為0 2017-07-22T17:43:59.691-0800: [GC (Allocation Failure) 2017-07-22T17:43:59.691-0800: [ParNew: 43604K->0K(46080K), 0.0065182 secs] 43604K->2675K(125952K), 0.0065664 secs] [Times: user=0.01 sys=0.01, real=0.00 secs] //分配3M不回收的對象,經歷一次YGC,此時age=1 2017-07-22T17:44:02.708-0800: [GC (Allocation Failure) 2017-07-22T17:44:02.708-0800: [ParNew: 40731K->3072K(46080K), 0.0050035 secs] 43406K->5747K(125952K), 0.0050444 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] //此時可以看到,3M的對象也被晉升到了Old區,這可以證明,如果只靠MaxTenuringThreshold來決定多少次YGC才晉升到Old區的話,此時age=1,並沒有達到閾值。 //因為此時3m達到TargetSurvivorRatio=60(5M*60=3m)的要求,那么前一次YGC,會重新計算對象晉升的threshold=min(age, MaxTenuringThreshold) = min(1,3) = 1次,所以此時晉升到了Old區 2017-07-22T17:44:05.722-0800: [GC (Allocation Failure) 2017-07-22T17:44:05.722-0800: [ParNew: 43806K->0K(46080K), 0.0060735 secs] 46481K->5747K(125952K), 0.0061215 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] GC end! Heap par new generation total 46080K, used 18003K [0x00000007b3800000, 0x00000007b6a00000, 0x00000007b6a00000) eden space 40960K, 43% used [0x00000007b3800000, 0x00000007b4994d88, 0x00000007b6000000) from space 5120K, 0% used [0x00000007b6000000, 0x00000007b6000000, 0x00000007b6500000) to space 5120K, 0% used [0x00000007b6500000, 0x00000007b6500000, 0x00000007b6a00000) concurrent mark-sweep generation total 79872K, used 5747K [0x00000007b6a00000, 0x00000007bb800000, 0x00000007c0000000) Metaspace used 3267K, capacity 4494K, committed 4864K, reserved 1056768K class space used 354K, capacity 386K, committed 512K, reserved 1048576K 

另外你可以在JVM啟動參數中加上-XX:+PrintTenuringDistribution,該參數可以輸出age的額外信息。

2017-07-22T18:07:51.401-0800: [GC (Allocation Failure) 2017-07-22T18:07:51.401-0800: [ParNew Desired survivor size 3145728 bytes, new threshold 3 (max 3) - age 1: 2854440 bytes, 2854440 total : 39936K->2819K(46080K), 0.0136187 secs] 39936K->2819K(125952K), 0.0138705 secs] [Times: user=0.01 sys=0.01, real=0.01 secs] 2017-07-22T18:07:54.452-0800: [GC (Allocation Failure) 2017-07-22T18:07:54.452-0800: [ParNew Desired survivor size 3145728 bytes, new threshold 3 (max 3) - age 2: 2682504 bytes, 2682504 total : 43549K->2918K(46080K), 0.0172463 secs] 43549K->2918K(125952K), 0.0173506 secs] [Times: user=0.00 sys=0.00, real=0.02 secs] 2017-07-22T18:07:57.484-0800: [GC (Allocation Failure) 2017-07-22T18:07:57.484-0800: [ParNew Desired survivor size 3145728 bytes, new threshold 3 (max 3) - age 3: 2680152 bytes, 2680152 total : 43442K->2723K(46080K), 0.0115410 secs] 43442K->2723K(125952K), 0.0116179 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 2017-07-22T18:08:00.511-0800: [GC (Allocation Failure) 2017-07-22T18:08:00.511-0800: [ParNew Desired survivor size 3145728 bytes, new threshold 3 (max 3) : 43449K->0K(46080K), 0.0226608 secs] 43449K->2673K(125952K), 0.0228187 secs] [Times: user=0.03 sys=0.00, real=0.02 secs] 2017-07-22T18:08:03.547-0800: [GC (Allocation Failure) 2017-07-22T18:08:03.547-0800: [ParNew Desired survivor size 3145728 bytes, new threshold 1 (max 3) - age 1: 3145776 bytes, 3145776 total : 40731K->3072K(46080K), 0.0055686 secs] 43404K->5745K(125952K), 0.0056352 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 2017-07-22T18:08:06.572-0800: [GC (Allocation Failure) 2017-07-22T18:08:06.572-0800: [ParNew Desired survivor size 3145728 bytes, new threshold 3 (max 3) : 43806K->0K(46080K), 0.0068945 secs] 46479K->5745K(125952K), 0.0070480 secs] [Times: user=0.00 sys=0.01, real=0.00 secs] GC end! Heap par new generation total 46080K, used 18003K [0x00000007b3800000, 0x00000007b6a00000, 0x00000007b6a00000) eden space 40960K, 43% used [0x00000007b3800000, 0x00000007b4994d88, 0x00000007b6000000) from space 5120K, 0% used [0x00000007b6000000, 0x00000007b6000000, 0x00000007b6500000) to space 5120K, 0% used [0x00000007b6500000, 0x00000007b6500000, 0x00000007b6a00000) concurrent mark-sweep generation total 79872K, used 5745K [0x00000007b6a00000, 0x00000007bb800000, 0x00000007c0000000) Metaspace used 3273K, capacity 4494K, committed 4864K, reserved 1056768K class space used 354K, capacity 386K, committed 512K, reserved 1048576K


免責聲明!

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



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