您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# 如何通过jstack与jmap分析一次线上故障
## 前言
在Java应用的线上运维中,突发性能问题或内存泄漏是常见挑战。掌握`jstack`和`jmap`这两个JDK工具的组合使用,能够快速定位线程阻塞、死锁、CPU飙高及内存异常等问题。本文将通过一个真实案例,演示如何通过这两个工具进行系统化分析。
---
## 一、问题现象
某电商平台订单服务突然出现以下异常:
- 接口平均响应时间从50ms飙升到2000ms
- CPU利用率持续超过90%
- 频繁触发Full GC,Old区内存无法释放
- 监控系统显示线程池满载告警
---
## 二、工具准备
### 1. jstack核心功能
```bash
# 抓取线程快照(需Java进程PID)
jstack -l <pid> > thread_dump.log
# 带JVM内部信息输出
jstack -m <pid> > mixed_dump.log
# 生成堆内存直方图
jmap -histo <pid> > heap_histo.log
# 生成堆转储文件(生产环境慎用)
jmap -dump:live,format=b,file=heap.hprof <pid>
注意:执行jmap可能会引发STW,建议在低峰期操作并做好回滚准备
通过jstack获取3次间隔10秒的快照:
for i in {1..3}; do jstack -l $PID > thread_$i.log; sleep 10; done
使用grep
统计线程状态分布:
cat thread_*.log | grep java.lang.Thread.State | sort | uniq -c
输出显示:
45 java.lang.Thread.State: RUNNABLE
12 java.lang.Thread.State: BLOCKED
3 java.lang.Thread.State: WTING
关键发现:
- 大量线程卡在com.example.OrderService.processPayment()
方法
- 12个线程阻塞在java.util.concurrent.locks.ReentrantLock$NonfairSync.lock()
使用jstack自动检测:
jstack -l $PID | grep -A 10 "deadlock"
输出明确提示:
Found one Java-level deadlock:
Thread 0x00007f8934017800 waiting for ReentrantLock@0x6d28f6d1
Thread 0x00007f8934038800 holding ReentrantLock@0x6d28f6d1
生成内存直方图:
jmap -histo:live $PID | head -20
发现异常:
num instances bytes class name
----------------------------------------------
1: 120452 27481024 [B # 字节数组
2: 98234 18000000 com.example.CacheEntry
3: 78451 11200000 java.util.concurrent.ConcurrentHashMap$Node
内存问题: - CacheEntry对象异常堆积(本应不超过1万实例) - 配合MAT分析发现是本地缓存未设置TTL
// 修改锁获取顺序(遵循全局统一顺序)
public void processPayment() {
synchronized(inventoryLock) {
synchronized(paymentLock) {
// 业务逻辑
}
}
}
// 改用Guava Cache并设置失效策略
Cache<String, Object> cache = CacheBuilder.newBuilder()
.maximumSize(10000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
jstack
健康检查grep -A 20 "held locks"
追踪锁持有链-histo
确认是否需要-dump
kubectl cp
导出诊断文件# 示例:自动分析线程dump的脚本
import re
with open('thread_dump.log') as f:
content = f.read()
blocked = len(re.findall('BLOCKED', content))
print(f"阻塞线程比例:{blocked/total_threads:.1%}")
通过jstack+jmap的组合拳,我们不仅解决了本次复合型故障,更建立了以下认知: 1. 线程问题往往表现为CPU高但实际是等待状态 2. 内存问题需要结合多个时间点数据对比 3. 预防性分析比应急处理更重要
建议每月定期进行故障演练,将工具使用转化为团队肌肉记忆。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。