要排查GC问题,首先需要获取详细的GC日志。在启动Java应用时,添加以下JVM参数开启GC日志(适用于JDK 9及以上版本,JDK 8及以下需调整参数格式):
java -Xms512m -Xmx4g -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:/var/log/java/gc.log -jar your-app.jar
-Xms512m:初始堆内存512MB;-Xmx4g:最大堆内存4GB(根据应用需求调整,避免频繁扩容触发GC);-XX:+UseG1GC:使用G1垃圾收集器(适合大内存、低延迟场景,可根据应用特性选择Serial、Parallel、CMS等);-XX:+PrintGCDetails:输出GC详细信息(包括各代内存变化、回收时间等);-Xloggc:/var/log/java/gc.log:将GC日志输出到指定文件(便于长期存储和分析)。使用jstat命令实时查看GC的运行情况,重点关注年轻代(Young Generation)、老年代(Old Generation)、元空间(Metaspace)的使用率及GC频率:
jstat -gcutil <PID> 1000 5
<PID>:Java应用的进程ID(可通过ps -ef | grep java获取);1000:每隔1秒刷新一次数据;5:共输出5次结果(可根据需要调整)。Eden区使用率(E列):若持续接近100%,说明年轻代对象增长过快,可能触发频繁Minor GC;老年代使用率(O列):若持续增长且接近最大堆容量,可能即将触发Full GC;Full GC次数(FGC列):若数值较大(如每分钟超过1次),说明GC开销过大,需优化。GC日志中包含了每次GC的时间、类型(Minor GC/Full GC)、触发原因、耗时、各代内存变化等信息,需重点关注以下内容:
2025-11-08T10:30:45.123+0800: [GC (Allocation Failure) 100082K->0K(89600K), 0.0088371 secs]
2025-11-08T10:31:00.456+0800: [Full GC (Metadata GC Threshold) 10114K->9638K(294400K), 0.123456 secs]
GC表示Minor GC(年轻代);Full GC表示全局GC(老年代+年轻代);Allocation Failure(年轻代空间不足);Metadata GC Threshold(元空间不足);0.0088371 secs(Minor GC耗时);0.123456 secs(Full GC耗时,若耗时过长会影响应用性能)。gc.log文件,自动生成报告(包含GC次数、暂停时间、吞吐量、内存泄漏嫌疑等);java -jar gcviewer.jar gc.log命令启动,查看各代内存使用趋势、GC频率分布等。若GC频繁且堆内存无法释放(如老年代使用率持续增长),可能存在内存泄漏。需通过以下步骤排查:
jmap命令导出堆内存快照(需在应用运行时执行,可能短暂停顿):jmap -dump:live,format=b,file=heapdump.hprof <PID>
live:仅导出存活对象(减少文件大小);format=b:二进制格式;heapdump.hprof:导出文件路径。heapdump.hprof,查看支配树(Dominator Tree)、泄漏嫌疑报告(Leak Suspects Report),找出占用内存大的对象(如静态集合、未关闭的数据库连接、ThreadLocal未清理等)及引用链。根据GC日志和监控结果,调整JVM参数以优化GC性能:
-Xmx(最大堆内存)和-Xms(初始堆内存)(如从-Xms512m -Xmx4g调整为-Xms2g -Xmx4g),避免堆内存不足触发频繁GC;-Xmn(年轻代大小)(如-Xmn1g),减少对象晋升到老年代的频率;-XX:+UseG1GC改为-XX:+UseZGC(低延迟收集器,适合大内存场景);若应用吞吐量优先,可使用-XX:+UseParallelGC(并行收集器,适合多核CPU);-XX:MetaspaceSize(初始元空间)和-XX:MaxMetaspaceSize(最大元空间)(如-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m)。/var/log/java/目录需提前创建并赋权);