栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

GC问题排查实战五-G1日志分析以及动态年龄调整机制

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

GC问题排查实战五-G1日志分析以及动态年龄调整机制

GC问题排查实战五-G1日志分析以及动态年龄调整机制

G1分析

参数跑完后数据gc日志数据safepoint相关数据 动态年龄调整机制(ParNew作为例子)

hotspot相关源码jdk1.8-b26哪些收集器会用到这个机制这个机制在哪个阶段被使用年龄阈值在哪个阶段被使用 总结

G1分析

这次我们用G1试试。

参数

-Xms8192M -Xmx8192M -Xmn4096M -Xss1M -XX:+UseG1GC -XX:+PrintTenuringDistribution -XX:+PrintHeapAtGC -XX:+PrintReferenceGC -XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1 -XX:metaspaceSize=256M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/data/app/log/gc/gc.log -XX:ErrorFile=/data/log/error/error.log -XX:+HeapDumponOutOfMemoryError -XX:HeapDumpPath=/data/log/heap/heap_hprof.bin -Dfile.encoding=UTF-8

跑完后数据

gc日志数据

同样我们找高的点看看:

看看日志,这个日志比较详细,更加直白的会告诉你哪些步骤耗时,可以看到也是处理引用和拷贝对象,也就是复制的消耗:

然后我找个耗时小的看看:

可以看到这个消耗的比较少,拷贝的对象也不多,引用处理也不多:

safepoint相关数据

动态年龄调整机制(ParNew作为例子)

当GC之后检查幸存区的年龄分布,发现年龄累计(小于等于)已经超过幸存区的一半(-XX:TargetSurvivorRatio默认是50)了,这个时候其实是有个动态年龄计算规则,当累积的某个年龄大小超过了survivor区的一半时,取这个年龄和MaxTenuringThreshold中更小的一个值,作为新的晋升年龄阈值,刚好这个时候年龄2累计(等于小于)的大小刚好超过幸存区的一半了,所以这个时候晋升的年龄就是2,因此后一次GC处理就会把年龄为2的晋升过去了,而且这里可以看到new threshold 2 (max 6),比如最开始是6,年龄为1的没有超过幸存区的一半,所以没调整,没晋升,耗时不多:

第二次GC后发现年龄为2的累计居然超过了幸存区的一半,那就调整阈值,这次耗时不是晋升,是因为处理引用和幸存区复制的耗时,下一次会有晋升了:

第三次就有晋升,比较耗时,主要就是因为复制,以及上一次年龄为1的经过GC后没被清除,年龄变2了,然后阈值又是2,所以他们要晋升,年龄2的又超过幸存区一半了,那下次还有晋升,年龄阈值还是2:

第四次必然有晋升,比较耗时,但是阈值改回来了,以为最后剩下年龄2的没超过幸存区一半,下次处理就不会有晋升了:

后一次就没了晋升了,阈值没变,多了年龄是3的对象,但是累计也不超过幸存区的一半,耗时也少了:

hotspot相关源码jdk1.8-b26

当然这个也动态年龄调整以及晋升不是我自己猜的,看看相关源码,是累计的的值大于幸存区容量乘以TargetSurvivorRatio系数,然后后面有打印的话会打印:

后面打印的就是这堆东西:

哪些收集器会用到这个机制

那我们再看看这个调节是在哪些用到的,首先是默认的新生代收集器DefNewGeneration:

然后是G1CollectorPolicy:

还有一个ParNewGeneration:

这个机制在哪个阶段被使用

我们拿ParNewGeneration的收集过程看看,不过我能力有限,并不打算分析源码,只是把这个动态调节的位置展示下,可以看到这个调节的方法在最后被调用,后面都是打印日志了,也就是说是在收集阶段最后才会进行调整的,然后这个年龄就会影响后一次收集的对象晋升:

年龄阈值在哪个阶段被使用

我们再来看下对象晋升再哪里,再扫描弱引用的时候会调用ParNewGeneration的copy_to_survivor_space方法:

然后就是处理的时候,先判断年龄,小于阈值的就先从to区分配内存,失败的话就说明溢出了,然后就尝试放老年代,还不够的话记录晋升失败,当然幸存区放的下的话就对象年龄**+1**:

其实就是标记后,对活的对象进行年龄阈值判断,处理能不能放下,放下年龄**+1**,或者放不下晋升或者失败。

总结

通过这3种垃圾回收器回收年轻代的例子,想说明如果发现年老代收集的耗时很长,可以通过什么方式来排查,首先当然是要有足够的日志,比如引用处理,对象年龄,对象拷贝,像G1的话就很详细,当然还可能有safepoint的等待线程的问题,然后根据具体的日志内容进行分析,看看到底哪块是主要耗时,然后进行优化,举个例子,比如我不想那么早把这些生命周期很短的晋升到老年代,放置老年代频繁的GC,那我可以调大年轻代以及幸存区比例,让他尽可能在年轻代就被清除,当然还可以调整比较幸存区比例的那个参数,当然也不是一味的调大年轻代,如果刚好业务对象存活的时间久,就会在幸存区频繁的复制,也是耗时的,所以没有万能的策略,只有根据具体业务选择不同的策略,这个就要看对业务以及垃圾回收器的理解啦,当然多学点理论知识还是好的,JVM相对来说理论比较多,虽然貌似实战没啥用,但是知道总比不知道好,手里有剑跟有剑不用是两码事对吧。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/776048.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号