如何排查生产环境中Tomcat WebApp的线程泄漏问题
别担心,虽然你对Java和Tomcat不太熟,但咱们可以从你已经在用的工具入手,一步步定位出哪个WebApp在搞事情!
第一步:用你打开的JConsole先做基础排查
- 切换到Threads标签页,重点盯着那些数量持续增长的线程组,尤其是状态一直是
RUNNABLE或者WAITING却不释放的线程 - 选中一个可疑线程,点击Thread Dump生成线程栈。这里关键看栈帧里的类加载器信息——每个WebApp的类都跑在自己的
WebappClassLoader下,栈里会标注对应的WebApp上下文路径或者名称,直接就能对应到具体应用 - 另外留意线程名称:很多框架(比如Spring)会给线程命名带上应用标识,比如
AppX-Async-Task-3这种,一眼就能看出归属
第二步:用JDK自带的jstack生成完整线程栈(更精准)
- 先打开终端,用
jps命令找到Tomcat的进程ID(输出里的Bootstrap就是它) - 执行命令:
jstack <你的Tomcat进程ID> > thread_dump.txt,把完整线程栈导出到文件 - 打开文件后,搜索你的WebApp上下文路径(比如两个交互应用叫
OrderApp和PayApp,就搜这两个关键词),统计每个应用关联的线程数量。如果某个应用的线程数远超正常水平,且大量线程卡在相同的代码路径上,那它就是头号嫌疑人
第三步:试试Tomcat自带的泄漏检测工具(如果能启用的话)
- 去Tomcat的
conf/tomcat-users.xml里,添加一个拥有manager-gui权限的用户(照着文件里的注释配置就行) - 访问
http://<你的Tomcat地址>:<端口>/manager/html,登录后找到Find Leaks按钮点击——Tomcat会自动检测哪些WebApp存在类加载器泄漏(线程泄漏通常会伴随类加载器泄漏,因为线程会持有类加载器的引用) - 这个功能会直接告诉你可疑应用,非常省心
第四步:终极隔离测试(笨但有效)
- 如果上面的方法还拿不准,就做隔离验证:先停掉其中一个交互的WebApp,观察Tomcat的线程数量是否还持续增长
- 停掉A之后线程不再堆积?那就是A的问题;反之就是B的锅。这个方法虽然粗暴,但对不熟悉Java排查的人来说,绝对靠谱
额外小提醒
- 线程泄漏常见原因:异步任务没正确关闭、数据库连接/线程池资源没释放、监听器没移除、第三方库的BUG导致线程挂起
- 如果线程栈里看到
java.lang.Thread.sleep(无超时)、Object.wait(没唤醒),或者卡在某个第三方SDK的方法里,重点关注对应的应用
内容的提问来源于stack exchange,提问作者Rabarberski
相关产品推荐
相关产品推荐

