Jvisualvm
项目频繁YGC 、FGC问题排查
内存问题
对象内存占用、实例个数监控

对象内存占用、年龄值监控

通过上面两张图发现这些对象占用内存比较大而且存活时间也是比较常,所以survivor 中的空间被这些对象占用,而如果缓存再次刷新则会创建同样大小对象来替换老数据,这时发现eden内存空间不足,就会触发yonggc 如果yonggc 结束后发现eden空间还是不够则会直接放到老年代,所以这样就产生了大对象的提前晋升,导致fgc增加……
优化办法:优化两个缓存对象,将缓存对象大小减小。优化一下两个对象,缓存关键信息!
CPU耗时问题排查
Cpu使用耗时监控:

耗时、调用次数监控:

从上面监控图可以看到主要耗时还是在网络请求,没有看到具体业务代码消耗过错cpu……
调优堆内存分配
初始堆空间大小设置
活跃数大小是应用程序运行在稳定态时,长期存活的对象在java堆中占用的空间大小。也就是在应用趋于稳太时FullGC之后Java堆中存活对象占用空间大小。(注意在jdk8中将jdk7中的永久代改为元数据区,metaspace 使用的物理内存,不占用堆内存)
堆大小调整的着手点、分析点
- 统计Minor GC 持续时间
- 统计Minor GC 的次数
- 统计Full GC的最长持续时间
- 统计最差情况下Full GC频率
- 统计GC持续时间和频率对优化堆的大小是主要着手点,我们按照业务系统对延迟和吞吐量的需求,在按照这些分析我们可以进行各个区大小的调整
年轻代调优
年轻代调优规则
- 老年代空间大小不应该小于活跃数大小1.5倍。老年代空间大小应为老年代活跃数2-3倍
- 新生代空间至少为java堆内存大小的10% 。新生代空间大小应为1-1.5倍的老年代活跃数
- 在调小年轻代空间时应保持老年代空间不变
MinorGC是收集eden+from survivor 区域的,当业务系统匀速生成对象的时候如果年轻带分配内存偏小会发生频繁的MinorGC,如果分配内存过大则会导致MinorGC停顿时间过长,无法满足业务延迟性要求。所以按照堆分配空间分配之后分析gc日志,看看MinorGC的频率和停顿时间是否满足业务要求。
-
MinorGC频繁原因 MinorGC 比较频繁说明eden内存分配过小,在恒定的对象产出的情况下很快无空闲空间来存放新对象所以产生了MinorGC,所以eden区间需要调大。
-
年轻代大小调整 Eden调整到多大那,我们可以查看GC日志查看业务多长时间填满了eden空间,然后按照业务能承受的收集频率来计算eden空间大小。比如eden空间大小为128M每5秒收集一次,则我们为了达到10秒收集一次则可以调大eden空间为256M这样能降低收集频率。年轻代调大的同时相应的也要调大老年代,否则有可能会出现频繁的concurrent model failed 从而导致Full GC 。
-
MinorGC停顿时间过长 MinorGC 收集过程是要产生STW的。如果年轻代空间太大,则gc收集时耗时比较大,所以我们按业务对停顿的要求减少内存,比如现在一次MinorGC 耗时12.8毫秒,eden内存大小192M ,我们为了减少MinorGC 耗时我们要减少内存。比如我们MinorGC 耗时标准为10毫秒,这样耗时减少16.6% 同样年轻代内存也要减少16.6% 即192*0.1661 = 31.89M 。年轻代内存为192-31.89=160.11M,在减少年轻代大小,而要保持老年代大小不变则要减少堆内存大小至512-31.89=480.11M
堆内存:512M 年轻代: 192M 收集11次耗时141毫秒 12.82毫秒/次

堆内存:512M 年轻代:192M 收集12次耗时151毫秒 12.85毫秒/次

按照上面计算调优 堆内存: 480M 年轻带: 160M 收集14次 耗时154毫秒 11毫秒/次 相比之前的 12.82毫秒/次 停顿时间减少1.82毫秒

但是还没达到10毫秒的要求,继续按照这样的逻辑进行 11-10=1 ;1/11= 0.909 即 0.09 所以耗时还要降低9%。 年轻代减少:160*0.09 = 14.545=14.55 M; 160-14.55 =145.45=145M 堆大小: 480-14.55 = 465.45=465M 但是在这样调整后使用jmap -heap 查看的时候年轻代大小和实际配置数据有出入(年轻代大小为150M大于配置的145M),这是因为-XX:NewRatio 默认2 即年轻代和老年代1:2的关系,所以这里将-XX:NewRatio 设置为3 即年轻代、老年大小比为1:3 ,最终堆内存大小为:

MinorGC耗时 159/16=9.93毫秒

MinorGC耗时 185/18=10.277=10.28毫秒

MinorGC耗时 205/20=10.25毫秒

Ok 这样MinorGC停顿时间过长问题解决,MinorGC要么比较频繁要么停顿时间比较长,解决这个问题就是调整年轻代大小,但是调整的时候还是要遵守这些规则。
















