要解读Tomcat的GC信息,首先需要开启GC日志记录。通过修改Tomcat启动脚本(bin/catalina.sh或bin/catalina.bat),添加以下JVM参数:
-XX:+PrintGC(开启GC日志)、-XX:+PrintGCDetails(打印详细GC信息,包括各代内存变化)、-XX:+PrintGCDateStamps(打印GC发生的日期和时间戳)、-XX:+PrintGCTimeStamps(打印GC发生相对于JVM启动的时间);-Xloggc:/path/to/gc.log(指定GC日志文件的保存路径,如/usr/local/tomcat/logs/gc.log);-XX:+UseGCLogFileRotation(开启日志滚动,避免单个文件过大)、-XX:NumberOfGCLogFiles=5(保留最近5个日志文件)、-XX:GCLogFileSize=20M(每个日志文件最大20MB)。配置完成后,重启Tomcat使参数生效(systemctl restart tomcat或./startup.sh)。
GC日志的每一行都包含时间、GC类型、内存变化、耗时等关键信息,以下是常见字段的含义:
yyyy-MM-ddTHH:mm:ss.SSS±HH:mm(如2024-03-10T12:34:56.789-0800),部分日志会额外显示相对于JVM启动的时间(如0.150秒,表示JVM启动后0.15秒发生GC)。[GC(如[GC (Allocation Failure),表示因年轻代空间不足触发);[Full GC(如[Full GC (System),表示系统级Full GC,通常由显式调用System.gc()或内存不足触发)。[区域名称: GC前使用量->GC后使用量(总容量)]。例如:[PSYoungGen: 4096K->1024K(8192K)]表示年轻代(PSYoungGen)GC前使用了4096K,GC后剩余1024K,总容量为8192K;4096K->2048K(16384K)表示整个堆GC前使用了4096K,GC后剩余2048K,总容量为16384K。X.XXXXXX secs(如0.0023457 secs),部分日志会进一步拆分用户态时间(user)、系统态时间(sys)、实际耗时(real)(如[Times: user=0.00 sys=0.00, real=0.00 secs]),其中real时间最能反映GC对应用的影响。Tomcat默认使用Parallel GC(吞吐量优先),也可配置为CMS(响应时间优先)或G1(平衡吞吐量与延迟),不同收集器的日志格式差异较大:
[GC (原因) [PSYoungGen: Eden使用量->Survivor使用量(Eden容量)] 堆使用量->堆剩余量(堆容量), 耗时];[Full GC (原因) [PSYoungGen: 年轻代GC前后变化] [PSOldGen: 年老代GC前后变化] [PSPermGen: 永久代GC前后变化], 堆总变化, 耗时]。[1 CMS-initial-mark: 老年代使用量(容量)])、并发标记([CMS-concurrent-mark: 耗时])、重新标记([CMS-remark: 老年代变化])、并发清除([CMS-concurrent-sweep: 耗时])等阶段,最后输出Full GC的总耗时。[GC global concurrent marking])、年轻代回收([GC pause (young))、混合回收([GC pause (mixed))等阶段,会记录每个阶段的耗时和内存回收情况(如[Eden: 使用量->0(容量)], [Survivors: 使用量->新Survivor使用量(容量)], [Old: 前使用量->后使用量(容量)])。通过解读GC日志,可以识别应用的内存使用问题,为调优提供依据:
-Xms(初始堆)、-Xmx(最大堆)、-Xmn(年轻代)参数。-XX:SurvivorRatio),需增大年轻代或调整Survivor区大小;-XX:MaxTenuringThreshold调整对象晋升阈值)或优化应用内存使用(减少长生命周期对象)。-XX:PretenureSizeThreshold调整);GC原因(如Allocation Failure、System.gc()、Metadata GC Threshold)能提示GC触发的根源。例如,频繁的Allocation Failure表示年轻代容量不足;System.gc()表示应用显式调用了垃圾回收(需检查代码中是否有System.gc()调用)。手动分析GC日志较为繁琐,可使用以下工具实现可视化分析,快速定位问题:
通过以上步骤,可以全面解读Tomcat日志中的GC信息,识别应用的内存问题,并针对性地进行调优(如调整堆大小、更换收集器、优化代码),提升Tomcat应用的性能和稳定性。