问题排查报告
问题背景
- 发生时间:2023-07-15 上午
- 现象:
Tomcat进程持续运行,但无法响应请求(假死),持续约20分钟。
系统访问卡顿,网页无法加载。
系统资源排查
通过以下命令检查基础资源占用:
top # CPU监控(发现异常进程7020)
free -h # 内存监控
df -hl # 磁盘监控
PID USER %CPU COMMAND
23328 root 399.6 java
关键发现:
- CPU占用近400%+
通过top -Hp 23328定位异常线程:

## 使用过命令强制输出23328的堆栈信息从而分析出可能出现内存泄露的代码(-F:强制执行,CPU打满的情 况下一定要强制输出,不然执行很慢甚至可能无法得到执行结果) jstack -F 23328 > thread_dump_F.txt - JVM内存占用99%
jmap -heap输出显示内存耗尽:PSYoungGen used 1332687K/1396736K (99%) // 年轻代 ParOldGen used 5401292K/5401600K (99%) // 老年代
根因分析过程
-
堆内存快照分析
紧急生成Heap dump:jmap -dump:live,format=b,file=heapdump.hprof 7020- 使用MAT/Eclipse分析发现:
对象XXXX的实例数异常增多(内存泄漏) - 泄漏路径:
XXXX对象→ 被本地缓存强引用 → 无法被GC回收
- 使用MAT/Eclipse分析发现:
-
线程栈分析
jstack -F输出显示:- Tomcat所有200个工作线程均处于
waiting for monitor entry(锁竞争) - 线程阻塞原因为:频繁Full GC导致系统卡顿,形成恶性循环:
- Tomcat所有200个工作线程均处于
问题总结
| 关键问题 | 根本原因 | 导致后果 |
|---|---|---|
| 内存泄漏 | 本地缓存强引用XXXX对象不释放 | 老年代持续占满 |
| 线程阻塞 | Full GC导致系统停顿 | Tomcat线程池耗尽 |
| 假死现象 | GC线程与业务线程资源竞争 | 请求堆积无响应 |
为什么未触发OOM?
- 内存泄漏是渐进过程,当泄漏速度 ≈ GC回收速度时:
Full GC持续尝试回收内存(暂停业务线程),但始终无法释放足够空间。
此时系统进入 “卡死”状态:既未崩溃,又无法处理新请求。
修复建议
-
修复内存泄漏
- 检查
XXXX对象的缓存逻辑,改用弱引用或增加过期机制 - 避免静态集合长期持有对象
- 检查
-
JVM参数优化
-XX:+UseG1GC // G1收集器更适合大堆 -XX:MaxGCPauseMillis=200 // 控制GC停顿时间 -XX:InitiatingHeapOccupancyPercent=45 // 更早启动并发GC -
增加监控
- 添加Prometheus+Grafana监控堆内存/GC频率
- 设置阈值告警(如Old Gen >80%持续5分钟)
讨论点
- 是否遇到过类似缓慢内存泄漏导致假死的场景?
- 对于服务中程序设计,有哪些最佳实践可避免此类问题?

8055

被折叠的 条评论
为什么被折叠?



