温馨提示×

Ubuntu Tomcat日志中内存泄漏如何检测

小樊
33
2025-12-13 23:54:12
栏目: 智能运维

Ubuntu Tomcat 内存泄漏检测与定位

一 从日志与 GC 入手

  • 启用并收集垃圾回收日志,观察是否存在频繁的 Full GC、GC 后老年代占用持续上升等异常模式。将以下参数加入 $CATALINA_HOME/bin/catalina.shJAVA_OPTS 并重启:
    • -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:$CATALINA_BASE/logs/gc.log
    • 使用命令持续跟踪日志:tail -f $CATALINA_BASE/logs/gc.log。若发现 Full GC 后 Old Gen 使用率几乎回到高点,往往意味着对象无法被回收,有泄漏嫌疑。
  • 检查 catalina.outlocalhost_access_log 是否伴随 OutOfMemoryError、线程数暴涨、响应时间陡增等异常,这些现象常与内存压力相关。

二 打开 Tomcat 内置泄漏检测

  • conf/context.xml 或应用的 META-INF/context.xml 中添加资源泄漏监听器,用于发现未关闭的资源(如 JDBC 连接、语句、结果集等):
    • 示例:
      <Context>
        <Listener className="org.apache.catalina.core.StandardContextLeakDetectionListener"
                  threshold="10000"/>
      </Context>
      
    • 当资源超过 threshold(毫秒) 未释放时,Tomcat 会在日志中输出警告,便于快速定位泄漏点。

三 生成并分析堆转储

  • 发生 OOM 时自动导出堆转储(推荐,生产可用):在 catalina.shJAVA_OPTS 增加
    • -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/tomcat/heapdump
    • 确保目录存在且磁盘空间充足;生成的 .hprof 文件可用 Eclipse MATVisualVM 分析,MAT 的 Dominator Tree 与引用链能直观定位泄漏对象与根因。
  • 手动触发堆转储(便于复现问题或在线排查):
    • 获取 Tomcat 进程 PID:ps -ef | grep tomcat
    • 导出:jmap -dump:format=b,file=/var/log/tomcat/heap-$(date +%F-%H%M%S).hprof [PID]
    • 若只需存活对象:jmap -dump:live,format=b,file=heap-live.hprof [PID]
  • 不建议长期使用 -agentlib:hprof 代理做持续 profiling,其对性能影响较大;仅在短时诊断场景下临时使用。

四 实时监控与对比

  • 命令行快速观测(无需图形界面):
    • jstat -gcutil [PID] 1000:每秒输出 GC 统计,关注 YGC/YGCT、FGC/FGCT、GCT 与老年代使用率变化。
    • jcmd [PID] GC.run_finalization / jcmd [PID] VM.gc:触发一次 Full GC 进行对比观察(谨慎在生产使用)。
  • 图形化与远程监控:
    • JConsole / VisualVM 通过 JMX 连接 Tomcat,实时查看堆内存、类加载、线程与 MBean(如 Catalina:type=DataSource*)。
    • 结合 Prometheus + GrafanaTomcat Manager 做长期趋势与告警,便于在日志之外建立可观测性基线。

五 常见线索与修复要点

  • 日志线索:
    • OutOfMemoryError: Java heap spaceGC overhead limit exceeded
    • catalina.out 中出现线程泄漏迹象(线程数持续增长、无法创建新线程)。
    • LeakDetectionListener 输出的未关闭资源警告(JDBC、文件流等)。
  • 修复要点:
    • 使用 try-with-resourcesfinally 块确保 Connection/Statement/ResultSetInputStream/OutputStream 等被关闭;优化连接池配置与超时。
    • 排查缓存与静态集合的无限增长,避免长生命周期对象持有短生命周期对象引用。
    • 结合 MAT Dominator Tree 找到“最大占用对象”与“GC Roots 引用链”,定位到具体类与代码行。

0