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啦。接下来的日志就是之前看到过的:
好了,这次先对新生代晋升的阈值有个大致的印象,下次会来看一下它是如何动态的变化进行晋升的。