实例演示MaxTenuringThreshold参数及阈值动态调整策略

在上一次【https://www.cnblogs.com/webor2006/p/11031563.html】学习了一个新的JVM对象晋升到老年代的参数“MaxTenuringThreshold”,它的具体作用回忆一下:

简单来说就是用来控制哪些对象的年龄超过了这个最大值就会晋升到老年代,而对于对象晋升的参数其实在之前还有一个类似的【https://www.cnblogs.com/webor2006/p/11025817.html】,如下:

它有个注意事项就是需要配合着这个参数一起使用:

它是用来控制当对象的大小达到多少时,则会晋升为老年代,而上一次控制的是对象的年龄,维度不一样。

这次会用一个综合的例子来对上一次学习的“MaxTenuringThreshold”参数透彻的理论它在对象晋升中发挥的作用,首先新建一个类:

这程序编写有啥意思呢,其实就是通过调用myGc方法来创建对象,然后当myGc方法执行完之后它里面的对象会立马回收,来查看整个GC的一个情况,接着再重复多调几次:

最后再定义三个字节数组,然后再执行myGc(),如下:

好,至此整个例子就编写完了,之所以程序写得这么绕一切都是为了说明"MaxTenuringThreshold"这个参数在gc中所发挥的作用,目前在不加jvm参数之前直接运行结果是比较平淡无奇的:

接着咱们给增加JVM的参数,来观看整个GC的情况,基本上大多数参数都是之前使用过的,也有新参数,下面来加一下:

紧接着第四参数为新参数,如下:

该参数的作用是当某一个survivor空间已经存活的对象如果已经占据了这个survivor空间的60%,那么会重新计算晋升的阈值而不是直接使用"MaxTenuringThreshold"配置的值,比如说Survivor空间是10M的大小,也就是说Survivor空间中已存活的对象的容量已经超过了6M的话,就会重新计算对象晋升的阈值了,而不是使用"MaxTenuringThreshold"所设置的值了,接着继续设置参数:

最后一个参数则为我们讨论的主角:

接下来运行看下结果,此时的结果就异常的丰富了:

/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/bin/java -verbose:gc -Xms200M -Xmn50M -XX:TargetSurvivorRatio=60 -XX:+PrintTenuringDistribution -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:MaxTenuringThreshold=3 -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.MyTest4
2019-06-18T22:11:29.805-0800: [GC (Allocation Failure) 2019-06-18T22:11:29.805-0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 3 (max 3)
- age   1:    1401992 bytes,    1401992 total
: 40551K->1397K(46080K), 0.0014185 secs] 40551K->1397K(199680K), 0.0014813 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
111111
2019-06-18T22:11:30.814-0800: [GC (Allocation Failure) 2019-06-18T22:11:30.814-0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 3 (max 3)
- age   1:     340728 bytes,     340728 total
- age   2:    1390544 bytes,    1731272 total
: 42136K->1786K(46080K), 0.0036079 secs] 42136K->1786K(199680K), 0.0036664 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
222222
2019-06-18T22:11:31.827-0800: [GC (Allocation Failure) 2019-06-18T22:11:31.827-0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 3 (max 3)
- age   1:         56 bytes,         56 total
- age   2:     340080 bytes,     340136 total
- age   3:    1390200 bytes,    1730336 total
: 42304K->1846K(46080K), 0.0015881 secs] 42304K->1846K(199680K), 0.0016395 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
333333
2019-06-18T22:11:32.839-0800: [GC (Allocation Failure) 2019-06-18T22:11:32.839-0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 3 (max 3)
- age   1:         56 bytes,         56 total
- age   2:         56 bytes,        112 total
- age   3:     340056 bytes,     340168 total
: 42569K->636K(46080K), 0.0034541 secs] 42569K->2005K(199680K), 0.0034946 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
444444
2019-06-18T22:11:33.849-0800: [GC (Allocation Failure) 2019-06-18T22:11:33.849-0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 1 (max 3)
- age   1:    3145832 bytes,    3145832 total
- age   2:         56 bytes,    3145888 total
- age   3:         56 bytes,    3145944 total
: 41365K->3213K(46080K), 0.0030496 secs] 42734K->4938K(199680K), 0.0030899 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
555555
2019-06-18T22:11:34.859-0800: [GC (Allocation Failure) 2019-06-18T22:11:34.859-0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 3 (max 3)
- age   1:         56 bytes,         56 total
: 43946K->17K(46080K), 0.0033201 secs] 45671K->4814K(199680K), 0.0033645 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
666666
hello world
Heap
 par new generation   total 46080K, used 15972K [0x0000000740000000, 0x0000000743200000, 0x0000000743200000)
  eden space 40960K,  38% used [0x0000000740000000, 0x0000000740f94990, 0x0000000742800000)
  from space 5120K,   0% used [0x0000000742800000, 0x00000007428046f0, 0x0000000742d00000)
  to   space 5120K,   0% used [0x0000000742d00000, 0x0000000742d00000, 0x0000000743200000)
 concurrent mark-sweep generation total 153600K, used 4796K [0x0000000743200000, 0x000000074c800000, 0x00000007c0000000)
 Metaspace       used 3167K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 349K, capacity 386K, committed 512K, reserved 1048576K

Process finished with exit code 0

日志比较多,下面来仔细分析一下,首先可以看到目前的每次GC都会显示时间戳了,如下:

当然就是这个JVM参数起的作用啦:

接下来看第一次GC:

其中这个就是我们新生代指定的垃圾收集器:

该参数发挥的作用:

那这个3M是如何得知的呢?其实是这样的:我们指定新生代的总大小为50M:

而没有指定Eden和Survivor之间比例默认就是按8:1:1来分配的,所以是40:5:5,也就是一个Survivor占据的空间就为5M,而此时咱们又指定了一个这个比例:

而5*60%=3M,所以正好是日志中输出的结果,也就说明了如果Survivor超过3M了则需要重新计算阈值了,继续分析:

接着来看第二次GC:

其中可以发现:

接着分析第三次GC:

此时就得注意啦!!!

接着再看第四次GC:

接着看第五次GC的情况:

这个时候情况就发生了比较大的变化了:

注意:当阈值为1时,会一次性将GC之后的所有年龄的对象都晋升到老年代,继续看最后一次GC:

最后看一下堆的情况:

以上就是对于阈值的一个整体认识,从上面这个具体例子就可以彻底对阈值对于GC是如何作用的有所了解啦。

原文地址:https://www.cnblogs.com/webor2006/p/11031979.html