MaxTenuringThreshold與閾值的動態調整理論詳解


今天會學習“MaxTenuringThreshold”這樣一個新的JVM參數,編寫的示例還是會基於上一次的代碼,新建個類,如下:

接下來給它設置JVM的參數,具體如下:

而接下來會新增三個參數:

這個在之前已經使用過,只是木有配置到JVM參數中,回憶下:

其實就是打印出JVM的啟動參數,接下來再添加兩個新的參數:

那這倆參數的含義是啥呢?下面來對它們有個認識:

-XX:MaxTenuringThreshold作用:在可以自動調節對象晉升(Promote)到老年代閾值的GC中,設置該閾值的最大值。【啥意思?當一個對象在新生代中經歷過Minor GC之后對象的年齡就+1,原來0歲此時就變為1了,當又經歷一次回收之后依然沒有被回收則年齡就變為2了,而我們給這參數設置的最大參數為5,假如對象的年齡變為6超些我們設置的最大的這個5時,該對象就會從新生代晉升到老年代當中,注意:這里是一個極其理想的情況,但是實際它是可能自動調節的,可能年齡到了2還沒達到我們設定的5也將其對象晉升到老年代了,但是最大值不可能超過我們設置的這個值的,也就是不可能對象的年齡到了6還沒有被晉升】該參數的默認值是15,CMS【Concurrent Mark Sweep收集器,參考:https://www.cnblogs.com/webor2006/p/10982448.html】中默認值為6,G1中默認為15【為啥是15?因為在JVM中,該數值是由四個bit來表示的,所以最大值為1111,轉換十進制則為15】。經歷了多次GC后,存活的對象會在From Survivor和To Survivor之間來回存放,而這里面的一個前提則是這倆空間有足夠的大小來存放這些數據,在GC算法中,會計算每個對象年齡的大小,如果達到某個年齡后發現總大小已經大於了一個Survivor空間的50%【也就是在Survivor中有一半以上的空間都已經被多次GC依然沒有被回收的對象所占據了】,那么這時候就需要調整閾值,不能再繼續等到默認的15次GC后才完成晉升,因為這樣會導致Survivor空間不足【這是一件非常可怕的事情,因為會導致很多新的對象直接就晉升到了老年代】,所以需要調整閾值,讓這些存活對象盡快完成晉升,來釋放Survivor空間

-XX:+PrintTenuringDistribution:表示打印年齡為幾的對象占多少字節的一些詳細信息。

好,加上了這些參數之后接下來咱們來運行一下看輸出:

/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/bin/java -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+PrintCommandLineFlags -XX:MaxTenuringThreshold=5 -XX:+PrintTenuringDistribution -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/tools.jar:/Users/xiongwei/Documents/workspace/IntelliJSpace/jvm_lectue/out/production/classes:/Users/xiongwei/.gradle/caches/modules-2/files-2.1/mysql/mysql-connector-java/5.1.34/46deba4adbdb4967367b013cbc67b7f7373da60a/mysql-connector-java-5.1.34.jar:/Users/xiongwei/.gradle/caches/modules-2/files-2.1/cglib/cglib/3.2.0/bced5c83ed985c080a24dc5a42b0ca631556f413/cglib-3.2.0.jar:/Users/xiongwei/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm/5.0.3/dcc2193db20e19e1feca8b1240dbbc4e190824fa/asm-5.0.3.jar:/Users/xiongwei/.gradle/caches/modules-2/files-2.1/org.apache.ant/ant/1.9.4/6d473e8653d952045f550f4ef225a9591b79094a/ant-1.9.4.jar:/Users/xiongwei/.gradle/caches/modules-2/files-2.1/org.apache.ant/ant-launcher/1.9.4/334b62cb4be0432769679e8b94e83f8fd5ed395c/ant-launcher-1.9.4.jar com.jvm.gc.MyTest3
-XX:InitialHeapSize=20971520 -XX:InitialTenuringThreshold=5 -XX:MaxHeapSize=20971520 -XX:MaxNewSize=10485760 -XX:MaxTenuringThreshold=5 -XX:NewSize=10485760 -XX:+PrintCommandLineFlags -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintTenuringDistribution -XX:SurvivorRatio=8 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC 
[GC (Allocation Failure) 
Desired survivor size 1048576 bytes, new threshold 5 (max 5)
[PSYoungGen: 7167K->496K(9216K)] 7167K->6648K(19456K), 0.0052608 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 496K->0K(9216K)] [ParOldGen: 6152K->6487K(10240K)] 6648K->6487K(19456K), [Metaspace: 2649K->2649K(1056768K)], 0.0082365 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
hello world
Heap
 PSYoungGen      total 9216K, used 2290K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 8192K, 27% used [0x00000007bf600000,0x00000007bf83c9a0,0x00000007bfe00000)
  from space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
  to   space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
 ParOldGen       total 10240K, used 6487K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
  object space 10240K, 63% used [0x00000007bec00000,0x00000007bf255d40,0x00000007bf600000)
 Metaspace       used 2656K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 287K, capacity 386K, committed 512K, reserved 1048576K

Process finished with exit code 0

下面稍加解讀一下:

很明顯這句的輸出是因為這個JVM參數的影響:

表示新生代晉升的一個閾值情況,很顯然這個打印就是我們這節新加的參數所致:

其中"new threshold 5"就是默認初始化的閾值大小為5,那這個又代表啥意思呢?

其中1048576就是為1M,因為總新生代的大小為10M,而8:1:1,那當然survivor的大小就是1M啦。接下來的日志就是之前看到過的:

好了,這次先對新生代晉升的閾值有個大致的印象,下次會來看一下它是如何動態的變化進行晉升的。


免責聲明!

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



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