【JVM调优】频道服务 FullGC频率优化
一.背景
核心服务高峰期FGC频率过高,优化FGC频率,提高核心服务稳定性,本次以频道服务 nn-channel-business 为案例
Java环境:JDK8
二.优化前数据
1.JVM 启动参数如下
-Dname=nn-channel-business -Dfile.encoding=utf-8 -Dspring.profiles.active=prod -Duser.timezone=Asia/Shanghai -Xms3072M -Xmx3072M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs/ -Dlog4j2.formatMsgNoLookups=true -Dlog4j.formatMsgNoLookups=true -javaagent:/skywalking-agent/agent/skywalking-agent.jar -Dskywalking.agent.service_name=nn-channel-business -Dskywalking.collector.backend_service=xx.xx.xx.xx:11800
垃圾回收器组合
PS Scavenge(年轻代) + PS MarkSweep(也叫做 Parallel Old)(老年代)
内存分配
年轻代:1G,其中,因为以上垃圾收集器组合,年轻代内存空间(Eden区 和 S区)会自适应动态分配内存,实际Eden区空间:970~990M,Surviror区空间 10~30M
老年代:2G
2.JVM监控数据
日期:2025/04/04-2025/04/07
QPS:单实例峰值20QPS


三.原因分析
可能的原因如下:
1. 业务代码 & 第三方框架内存泄漏
2. 大对象频繁创建,直接分配老年代
3 .内存分配不合理,内存设置过小
4. 系统负载过高,高并发请求,大数据量的业务操作
四.问题排查过程
1. 业务代码 & 第三方框架内存泄漏
分析:查询高峰期内存快照,查询最大的内存占用是char[]对象

分析引用,关注320M的char数组对象,可以看到FastJSON序列化导致大量的引用

查询到GitHub有类似 issue
地址:https://github.com/alibaba/fastjson/issues/3751
问题描述:单个线程对应的ThreadLoacl存在128K 本地缓存,目的缓存序列化的字符串,提高序列化效率,但也导致了内存浪费
频道服务 tomcat 主线程数量 和 openfeign + hystrix 线程池 数据量合计在500,预计最高占用不超过100M内存,业务侧可接受
结论
由于JSON序列化导致的内存占用对FGC的影响较小,由于这块内存是缓慢增加至128K后会稳定不会上升,对于老年代的FGC的影响在4%(100M/2048M)
因此JSON序列化内存占用这个原因不是导致FGC频繁的原因,且内存快照没有发现其他的内存泄漏场景,因此该可能性可以排除
2. 大对象频繁创建,直接分配老年代
分析
分析目前频道业务场景,核心业务接口
/channel/business/findServerAndPluginByServerId/{serverId} 内嵌调用,查询语音房列表和组队列表(全量返回)
/channel/business/enterPersonalTopicServerById 客户端调用,查询语音房列表和组队列表(全量返回)
1.高峰期以上两个接口调用趋势与DAU增长趋势一致
2.以上两个接口会返回大数组对象(最高1500个语音房),数组对象分配需要连续的内存空间,考虑是否因为年轻代内存空间不足导致
基于以上考虑,需要进一步确认是Eden区内存不足还是Surviror区内存不足
处理方案
1.Eden区内存空间不足
调整JVM参数,增加启动参数: -Xmn1536M
数据如下:改善不明显

2. Survivor内存空间不足
调整JVM参数,考虑到垃圾收集器动态分配内存的问题,增加启动参数:-XX:-UseAdaptiveSizePolicy -XX:SurvivorRatio=8
数据如下:改善明显,降低至1.5FGC次/天

结论
综上,可以确认是因为Survivor区内存空间不足对应FGC的频率较大,由于内存分配的需要连续的空间,年轻代Eden区发生GC时,Survivor空间无法支撑对象分配,因此直接分配到老年代
3 .内存分配内存设置过小,垃圾收集器选用不合理(TODO )
1. 综合问题2的结论,在现有内存分配和垃圾收集器组合的情况下(3G),优化效果已达预期
2. 垃圾收集器选用不合理 //TODO 后续可以分析对比CMS 和 PS 的效率
4. 系统负载过高,高并发请求,大数据量的业务操作
1.无相关业务操作
五.总结
问题原因
频道业务形态,具有连续的大的数据对象,Eden区GC后,Survivor空间分配过小,对象直接分配到老年代,导致老年代FGC频率过高原因
解决方案
JVM 参数增加参数,禁止动态分配,固定Eden区和S区大小
-XX:-UseAdaptiveSizePolicy -XX:SurvivorRatio=8
优化效果
高峰期FGC频率由 8次-->1.5次,降低 80%
TODO
- 优化效果 是 在基于NN客户端(Web和PC) 现有业务场景和DAU 下的优化结果,如发生业务场景变更或DAU波动,需要进一步关注数据指标;
- 调研 CMS & PS 垃圾回收器在频道业务场景下的垃圾回收效率,关注对比数据,确认是否有进一步优化的空间;

浙公网安备 33010602011771号