内存泄漏是Tomcat应用中常见的高危问题,会导致堆内存持续增长、Full GC频繁、应用响应变慢甚至崩溃。通过Tomcat日志及相关工具的组合使用,可系统定位泄漏根源。以下是具体步骤:
首先需要通过Tomcat日志和监控工具识别内存泄漏的典型信号,这些迹象是后续分析的基础:
catalina.out、localhost.log或访问日志,若出现ThreadLocal泄漏警告(如The web application [xxx] created a ThreadLocal...but failed to remove it),或内存相关的OutOfMemoryError(如java.lang.OutOfMemoryError: Java heap space),可直接定位泄漏点。jstat -gcutil <pid> 1000(每秒刷新一次)或第三方工具(如VisualVM、JConsole)监控Tomcat进程的内存使用,若堆内存(尤其是老年代)使用量随时间持续上升,且Full GC后无明显下降,说明存在泄漏。GC日志能精准反映内存回收的状态,是判断内存泄漏的关键依据。需在Tomcat启动脚本(如catalina.sh或startup.bat)中添加以下JVM参数,开启详细GC日志:
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/path/to/tomcat/logs/gc.log
通过GC日志可重点分析:
[GC (Full GC) [PSYoungGen: 1024K->0K(1536K)] [ParOldGen: 10240K->5120K(10240K)]),若回收量很小(如老年代从10GB降到9.5GB),则表明有大量对象未被回收;堆转储文件(Heap Dump)是内存泄漏定位的“金钥匙”,它记录了某一时刻JVM堆内存中所有对象的状态(如对象类型、数量、引用链)。生成堆转储文件的常用命令为:
jmap -dump:format=b,file=/path/to/heapdump.hprof <pid>
其中<pid>为Tomcat进程ID(可通过jps -l获取)。生成后,使用Eclipse MAT(Memory Analyzer Tool)或VisualVM等工具分析:
byte[]、java.util.HashMap),判断是否为业务需要的对象;ThreadLocalMap.Entry→RequestContext→未关闭的数据库连接),找到阻止其被回收的根源(如静态集合持有对象引用、ThreadLocal未清理)。Tomcat自身日志会记录一些与内存泄漏相关的警告或错误,需重点关注:
ThreadLocal、Servlet实例),会在catalina.out中输出类似警告:“The web application [myapp] created a ThreadLocal…but failed to remove it when the web application was stopped”。这类警告可直接指向泄漏的组件(如MyServlet类中的ThreadLocal变量)。org.apache.tomcat.util.threads.TaskQueue)耗尽,会在日志中记录“Queue full”或“ThreadPool exhausted”,需检查是否因线程阻塞或任务堆积导致内存泄漏。通过上述步骤找到泄漏对象后,需结合应用代码进一步分析:
Connection、InputStream、FileOutputStream等对象,需检查代码中是否遗漏了close()调用(建议使用try-with-resources语法自动关闭资源);ThreadLocalMap.Entry对象,需检查是否在ThreadLocal使用后调用了remove()方法(线程池环境下,未清理的ThreadLocal会导致对象长期存活);Map、List对象,需检查是否在不再需要时清空集合(静态集合的生命周期与应用一致,会持续持有对象引用)。通过以上步骤,可系统利用Tomcat日志及工具定位内存泄漏问题。需注意的是,内存泄漏排查需结合“日志分析+工具验证+代码审查”,才能彻底解决问题。