CentOS 上 Tomcat 日志出现内存泄漏的处理流程
一 快速定位与日志判读
- 查看关键日志:重点关注 $CATALINA_HOME/logs/catalina.out 与 localhost..log,检索关键字 OutOfMemoryError、java.lang.OutOfMemoryError、以及 Tomcat 的资源泄漏告警(如 clearReferencesThreads、clearReferencesJdbc 等)。这些告警通常出现在应用停止或重启时,提示有线程、JDBC 驱动、类加载器等未正确释放。示例路径与命令:
- 查看日志:tail -f $CATALINA_HOME/logs/catalina.out
- 检索关键词:grep -i “OutOfMemoryError|clearReferences” $CATALINA_HOME/logs/catalina.out
- 判定内存区域:根据异常类型快速判断问题域,常见类型与含义如下:
- Java heap space:堆内存不足,对象分配失败,常见于集合/缓存无限增长、对象生命周期过长。
- PermGen space(Java 7 及更早):永久代/方法区不足,常见于类加载器泄漏、第三方库缓存。
- Metaspace(Java 8+):元空间不足,常见于动态生成类、热部署频繁、类加载器未释放。
- Tomcat 日志中的 clearReferences* 警告:指示 Web 应用停止后仍有线程、JDBC 驱动、类加载器等残留,属于资源/类加载器泄漏的高风险信号。
二 复现实战与监控取证
- 监控运行时指标:
- 使用 jstat -gcutil 1000 观察 YGC/YGCT、FGC/FGCT、GCT 与各区使用率,判断是否频繁 Full GC、老年代是否持续增长。
- 获取堆转储并分析:
- 生成堆转储:
- jmap -dump:live,format=b,file=heapdump.hprof
- 或 jcmd GC.heap_dump /path/to/heapdump.hprof
- 分析堆转储:
- 使用 Eclipse MAT 或 JProfiler 打开 .hprof,查看 Dominator Tree、Histogram、Leak Suspects,定位占用内存最多的对象及其 GC Roots 引用链,回溯到具体类/代码路径。
- 在线诊断与压测复现:
- 通过 jconsole / jvisualvm 连接目标 JMX 实例,观察堆、线程、类加载器变化;结合业务操作进行压测,观察对象是否“只增不减”。
三 常见根因与修复要点
- 代码与框架层
- 静态集合、缓存无界增长、监听器/回调未注销、ThreadLocal 使用后未清理、大对象未及时释放。
- 修复:控制缓存容量与过期策略、在 ServletContextListener.contextDestroyed 或框架销毁回调中清理资源、避免在请求线程中长期持有大对象引用。
- 资源泄漏
- 未关闭的 JDBC Connection/Statement/ResultSet、未注销的 Thread、未释放的 ClassLoader(热部署/多应用共用问题)。
- 修复:使用 try-with-resources 或 finally 可靠关闭资源;在应用停止时显式关闭线程池/定时任务;避免应用代码注册全局静态引用导致类加载器无法回收。
- 容器与配置层
- JVM 参数不当(堆过小、元空间/永久代不足)、GC 策略不匹配、频繁热部署导致类加载器堆积。
- 修复:结合负载合理设置堆与元空间、选择合适的 GC、减少不必要的热部署频率。
四 JVM 参数与配置示例
- 建议将内存与 GC 参数写入 $CATALINA_HOME/bin/catalina.sh 的 CATALINA_OPTS(避免污染全局 JAVA_OPTS),并按 Java 版本区分元空间/永久代设置:
- Java 8+(使用 Metaspace)
- CATALINA_OPTS=“$CATALINA_OPTS -server -Xms2g -Xmx2g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:$CATALINA_HOME/logs/gc.log”
- Java 7 及更早(使用 PermGen)
- CATALINA_OPTS=“$CATALINA_OPTS -server -Xms2g -Xmx2g -XX:PermSize=256m -XX:MaxPermSize=512m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:$CATALINA_HOME/logs/gc.log”
- 说明:
- -Xms/-Xmx 建议设为相同值以减少堆动态扩展带来的抖动;G1GC 适合大堆与停顿可控场景。
- 开启 GC 日志 便于回溯分析;堆转储建议仅在问题复现时抓取,避免频繁 Dump 影响性能。
五 上线后的持续预防与监控
- 启用 Tomcat 资源泄漏检测:在 conf/context.xml 或应用的 META-INF/context.xml 配置 LeakDetectionListener,对未释放资源进行阈值告警,便于早期发现泄漏趋势。
- 建立监控与告警:
- 使用 jstat 或 JMX 采集堆/GC/线程指标,结合 Prometheus + Grafana 设置阈值告警;发生 OutOfMemoryError 时联动采集 Heap Dump 与线程栈。
- 发布与运行时规范:
- 控制依赖与类加载范围,避免应用代码注册全局静态引用;热部署改为蓝绿发布/滚动升级,减少类加载器残留。