线上问题排查:如果JVM出现频繁FullGC该如何解决?

1.我们知道FullGC的触发条件大致情况有以下几种情况:

  • 程序执行了System.gc() //建议jvm执行fullgc,并不一定会执行

  • 执行了jmap-histo:live pid 命令 //这个会立即触发fullgc

  • 在执行minorgc的时候进行的一系列检查

1.执行Minor GC的时候,JVM会检查老年代中最大连续可用空间是否大于了当前 新生代所有对象的总大小。

2.如果大于,则直接执行MinorGC(这个时候执行是没有风险的)。

3.如果小于了,JVM会检查是否开启了空间分配担保机制,如果没有开启则直接改 为执行Full GC。 如果开启了,则JVM会检查老年代中最大连续可用空间是否大于了历次晋升到老 年代中的平均大小,如果小于则执行改为执行FullGC。

4.如果大于则会执行MinorGC,如果MinorGC执行失败则会执行FullGC

5.使用了大对象 //大对象会直接进入老年代

6. 在程序中长期持有了对象的引用 //对象年龄达到指定阈值也会进入老年代 对于我们的情况,可以初步排除1,2两种情况,最有可能是4和5这两种情况。为了 进一步排查原因,我们在线上开启了-XX:+HeapDumpBeforeFullGC。

注意: JVM在执行dump操作的时候是会发生stoptheword事件的,也就是说此 时所有的用户线程都会暂停运行。 为了在此期间也能对外正常提供服务,建议采用分布式部署,并采用合适的负 载均衡算法

2. JVM参数的设置

线上这个dubbo服务是分布式部署,在其中一台机子上开启了

  • -XX:HeapDumpBeforeFullGC,总体 JVM参数如下:

  • -Xmx2g

  • -XX:+HeapDumpBeforeFullGC

  • -XX:HeapDumpPath=.-Xloggc:gc.log-XX:+PrintGC

  • -XX:+PrintGCDetails

  • -XX:+PrintGCDateStamps

  • -XX:+UseGCLogFileRotation

  • -XX:NumberOfGCLogFiles=10

  • -XX:GCLogFileSize=100m

  • -XX:HeapDumpOnOutOfMemoryError

3. Dump文件分析

dump下来的文件大约1.8g,用jvisualvm查看,发现用char[]类型的数据占用了41% 内存,同时另外一个com.alibaba.druid.stat.JdbcSqlStat 类型的数据占用了35%的内 存,也就是说整个堆中几乎全是这两类数据。如下图:

查看char[]类型数据,发现几乎全是sql语句

接下来查看char[]的引用情况:

找到了JdbcSqlStat类,在代码中查看这个类的代码,关键代码如下:

其实到这里也就知道什么原因造成了这个问题,因为我们使用的数据源是阿里巴巴的 druid,这个druid提供了一个sql语句监控功能,同时我们也开启了这个功能。只需 要在配置文件中把这个功能关掉应该就能消除这个问题,事实也的确如此,关掉这个功 能后到目前为止线上没再触发FullGC

其他 如果用mat工具查看,建议把 “Keepunreachableobjects” 勾上,否则mat会把 堆中不可达的对象去除掉,这样我们的分析也许会变得没有意义。如下图: Window–>References 。另外jvisualvm 对ool 的支持不是很好,如果需要oql建议 使用mat。

 粉丝福利

40+最新Java场景题已整理成册,需要的小伙伴点击文末小卡片即可:

 近期或者明年有面试需求的小伙伴一定要拿回去在工作之外时间好好刷刷!!!

工作8小时的态度决定的是下限,空闲的8小时才决定上限。人活在世上,要吃饭,要追求物质,功利地讲,我们要做的只有一件事,超越别人就可以了。所以空闲8个小时就是你超越别人的最好的机会。别说上班一天很累,大家都累,你不更累一点,谈啥比别人强?

以上,共勉(手动抱拳)

<think>我们正在解决Java应用中频繁Full GC问题。根据提供的引用资料,我们可以总结出以下排查步骤和解决方法: 1. 监控分析:首先需要收集GC日志和内存使用情况,分析Full GC发生的频率和内存使用趋势。 2. 关联业务:将Full GC的发生与应用程序的业务操作关联,检查是否有特定操作导致内存泄漏或大量对象创建。 3. 堆内存分析:通过生成堆转储(Heap Dump)文件,使用分析工具(如MAT, VisualVM)检查内存中的对象,找出内存泄漏点。 4. 检查JVM参数:确认JVM参数设置是否合理,特别是堆大小(-Xmx, -Xms)、年轻代大小、老年代大小以及垃圾回收器的选择。 5. 代码优化:根据分析结果,优化代码,避免内存泄漏和不必要的对象创建。 下面我们详细展开:</think>### Java应用频繁Full GC排查解决方法 频繁Full GC通常由内存泄漏、对象分配不合理或JVM配置不当引起,以下是系统化的排查流程: #### 排查步骤 1. **监控数据收集** - 启用GC日志:添加JVM参数 `-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log` - 使用监控工具: - `jstat -gcutil <pid> 1000` 实时查看各内存区使用率 - `jmap -histo:live <pid>` 统计存活对象分布 - Prometheus + Grafana 可视化监控堆内存趋势[^3] 2. **内存泄漏分析** - 生成堆转储文件: ```bash jmap -dump:format=b,file=heapdump.hprof <pid> # 线上慎用,可能STW ``` - 使用MAT/Eclipse Memory Analyzer分析 `heapdump.hprof`,重点关注: - 重复对象(Duplicate Classes) - 支配树(Dominator Tree)中的大对象 - GC Roots引用链(Path to GC Roots)[^4] 3. **业务关联分析** - 对照GC时间戳与业务日志,检查Full GC是否与特定操作同步发生(如报表生成、批量处理)[^3] - 示例:某电商平台在每日订单导出后触发Full GC,定位到未关闭的数据库连接池[^1] 4. **JVM参数检查** - 验证关键参数合理性: ```bash java -XX:+PrintFlagsFinal | grep -Ei "MaxHeapSize|MetaspaceSize|SurvivorRatio" ``` - 常见问题: - 新生代过小(`-XX:NewRatio` 比例失衡) - 元空间溢出(`-XX:MaxMetaspaceSize` 不足) - 未启用CMS/GC日志(`-XX:+UseConcMarkSweepGC`)[^2] #### 解决方案 1. **代码层优化** - 修复内存泄漏:及时关闭资源(数据库连接、文件流) - 减少大对象分配:避免在循环内创建大数组/集合 - 对象池化:重用高频创建的对象(如DTO) 2. **JVM调优** - 调整堆大小:根据业务负载设置 `-Xmx` 和 `-Xms` - 优化新生代:增大 `-XX:NewSize` 减少过早晋升 - 更换垃圾回收器: - G1:`-XX:+UseG1GC`(推荐大堆场景) - ZGC:`-XX:+UseZGC`(低延迟要求) 3. **紧急缓解措施** - 临时扩容:增加堆内存上限 - 定时重启:通过cron job在低峰期重启服务 - 流量降级:限制触发内存问题的业务入口 > **案例参考**:某金融系统因未压缩JSON报文导致Full GC,通过 `-XX:+UseCompressedOops` 启用指针压缩降低内存占用20%[^2]。 #### 验证手段 ```bash # 压测后检查对象分配 jmap -histo <pid> | grep 'com.yourpackage' # 对比优化前后GC暂停时间 grep "Full GC" gc.log | awk '{print $11}' ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值