线上频繁FullGC完整排查流程

发布时间:2026/6/5 16:12:12

线上频繁FullGC完整排查流程 一、先明确FullGC触发常见原因老年代空间不足、内存泄漏/内存溢出大对象直接进老年代、频繁晋升MetaSpace元空间满、动态加载类过多System.gc()代码主动调用、RMI定时FullGCJVM参数不合理新生代太小、Survivor过小、晋升阈值异常堆内存分配过小、物理内存被其他进程抢占核心排查思路先抓现场 → 看GC日志定位类型 → 堆快照分析 → 代码定位 → 压测复现 → 调参优化二、阶段1紧急应急线上不能停服优先1. 基础信息采集# 查看java进程PIDjps-l# 实时看GC状态jstat-gcutilPID1000重点指标O老年代使用率持续上涨 → 内存泄漏/对象不停晋升到老年代M元空间持续涨满 → 类加载泄漏S0/S1长期几乎满、Eden快速打满 → 新生代过小对象频繁提前晋升老年代2. 临时规避业务优先保可用临时扩容-Xmx/-Xms增大堆缓解频繁FGC临时关闭RMI自动FullGC-Dsun.rmi.dgc.client.gcInterval3600000 -Dsun.rmi.dgc.server.gcInterval3600000临时下线可疑定时任务、批量导入、大文件解析接口三、阶段2采集GC日志定位FGC根因分类1. 开启/导出GC日志没提前配置则动态抓取JVM启动参数必备生产标配-Xloggc:/xxx/gc.log -XX:PrintGCDetails -XX:PrintGCDateStamps -XX:PrintHeapAtGC根据GC日志区分4大类FGC老年代占满触发FGC最常见日志关键字Allocation FailureEden耗尽→对象晋升老年代老年代不足触发FullGCMetaSpace满触发FGC日志Metaspace allocation failure动态代理、热加载、频繁创建ClassLoaderSystem.gc()主动触发日志Full GC (System.gc())代码/第三方包显式调用System.gc()CMS并发失败/晋升担保失败CMS收集器concurrent mode failure / promotion failed老年代预留空间不足担保失败触发STW FullGC四、阶段3dump堆快照定位占用内存的对象核心步骤抓堆时机FGC频繁、老年代占用率80%还没OOM时dump避免OOM后数据丢失方式1命令行dumpjmap-dump:formatb,fileheap.hprof PID# 生产dump建议加参数不阻塞业务jmap -dump:live,formatb,fileheap.hprof PID方式2OOM自动dump提前配置-XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/xxx/heap.hprof堆文件分析工具MATEclipse Memory Analyzer首选Leak Suspects泄漏可疑报告一键定位泄漏对象Dominator Tree支配树查看占用堆最多的对象Histogram按类统计实例数量、占用内存JProfiler、Arthas在线分析不用下载大hprof五、阶段4Arthas在线实时排查不用重启、不用dump大文件1. 安装启动Arthascurl-Ohttps://arthas.aliyun.com/arthas-boot.jarjava-jararthas-boot.jar常用排查命令# 1. 实时监控GCgc-i1000# 2. 查看堆内存实时分布heapdump--live/tmp/dump.hprof# 3. 查看对象实例数量快速找暴涨对象dashboard# 4. 追踪创建大量对象的方法trace 全类名 方法名# 5. 排查ClassLoader泄漏classloader六、阶段5按场景逐个定位代码问题场景1内存泄漏老年代缓慢涨每次FGC回收不掉多少内存常见泄漏点静态集合static List/Map无限add对象无移除逻辑ThreadLocal使用完未remove线程池复用线程导致对象常驻连接池、缓存本地Cache无过期淘汰数据只增不减第三方框架Mybatis拦截器、定时任务、异步线程未销毁对象MAT定位支配树找到超大对象 → 查看引用链Reference Chain → 找到业务代码场景2大对象频繁创建直接进老年代一次性读取超大文件、全表查数据库不分页返回全量List超大字符串拼接、一次性创建超大数组JVM参数-XX:PretenureSizeThreshold2M超过阈值直接进老年代频繁创建触发FGC场景3元空间满FGC动态生成代理类CGLIB频繁创建、Groovy脚本热加载自定义ClassLoader不停新建不卸载-XX:MaxMetaspaceSize配置过小场景4代码主动System.gc()第三方SDK、老版本RPC、定时任务里隐式调用System.gc()代码检索System.gc()全局关键字使用Arthaswatch拦截调用七、阶段6JVM参数优化分收集器G1/CMS/ZGC通用优化方向新生代大小Eden占堆1/3~1/2避免Eden过小频繁晋升调整SurvivorRatio、MaxTenuringThreshold晋升年龄减少过早晋升到老年代禁用显式GC-XX:DisableExplicitGC谨慎NIO依赖System.gc堆外内存则不能加合理设置MetaSpace-XX:MetaspaceSize256M -XX:MaxMetaspaceSize512MG1收集器主流生产-XX:UseG1GC -XX:MaxGCPauseMillis200 # 预期STW停顿 -XX:G1HeapRegionSize16MCMS老项目优化调高老年代预留空间-XX:CMSInitiatingOccupancyFraction70 -XX:UseCMSInitiatingOccupancyOnly避免并发失败FullGC八、阶段7复现验证上线落地优化本地/测试环境压测JMeter复现FGC修复代码后压测验证GC平稳上线灰度发布上线后持续监控GC指标PrometheusGrafana告警配置老年代使用率80%、10min内FullGC3次触发告警九、排查速记口诀先jstat看GC趋势 → 拉GC日志分FGC类型 → arthas在线查对象 → dump堆MAT找泄漏引用 → 改代码调JVM参数 → 压测验证上线

相关新闻