news 2026/10/22 12:12:55

jstat /jstack/jmap 详解 + 实战场景示例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
jstat /jstack/jmap 详解 + 实战场景示例

JDK 自带工具:jstat /jstack/jmap

前提:

这些命令属于JDK bin,不是 JRE;

只能抓本地 Java 进程,需要知道进程 PID,查看 PID 命令:jps -l(最常用)

jps=Java Virtual Machine Process Status Tool,JDK 自带工具,专门查看 Java 进程,不需要额外安装。

-l是 long(长格式)作用:输出PID + 主类全限定名 /jar 完整路径

# 查看java进程,拿到pid jps -l

假设示例中 Java 进程 PID =12345

一、jstat:JVM 运行状态统计工具(看 GC、类加载、编译等指标)

全称:JVM Statistics Monitoring Tool,JDK 自带,

实时采样监控 JVM 运行统计,最常用就是看 GC 情况,

jstat [-options] <pid> [间隔ms] [采样次数]

常用 option

gcGC 统计(最常用)
gccapacity堆各区域容量 + 当前占用
gcutilGC 百分比视图(推荐,一眼看使用率)
gccausegcutil + 最后一次 GC 原因
class类加载统计
compilerJIT 编译统计

场景 1:排查频繁 FullGC,观察 GC 指标(最常用)

需求:每 1000ms 输出一次,一共输出 10 次,查看 S0、S1、E、O、M 的GC 占比

jstat -gcutil 12345 1000 10

示例输出:

S0 S1 E O M CCS YGC YGCT FGC FGCT GCT 0.00 89.23 45.12 62.31 94.11 91.23 2145 32.123 12 2.456 34.579

字段解释:

  • S0/S1:Survivor0、Survivor1 使用率
  • E:Eden 区使用率
  • O:老年代 Old 使用率
  • M:元空间 Metaspace 使用率
  • YGC:年轻代 GC 次数;YGCT:YGC 总耗时
  • FGC:FullGC 次数;FGCT:FullGC 总耗时
  • GCT:GC 总耗时

✅ 判断点:

  1. O 老年代持续上涨,不断触发 FGC →内存泄漏
  2. FGC 次数持续飙升,FGCT 时间变长 → 严重卡顿

场景 2:查看堆内存各区域容量

jstat -gccapacity 12345 1000 5

可以看到 Eden、Survivor、Old 的最大容量、当前容量。

场景 3:查看类加载情况(排查类泄漏、元空间满)

jstat -class 12345

输出:加载类数量、卸载数量、耗时。如果类持续不断加载不卸载 → 元空间溢出。

二、jstack:线程栈分析工具(死锁、线程阻塞、CPU 高、线程池打满)

Java Stack Trace,JDK 自带工具,打印 JVM 内所有线程栈快照

作用:

  • Java 死锁
  • CPU100%(线程无限循环)
  • 线程阻塞、等待锁
  • 线程池耗尽、接口长时间 hang 住

语法:

jstack [-l] <pid>
  • -l:额外输出锁信息(long listing),排查死锁必加

⚠️ 如果进程卡死,可以加-F强制 dump(jstack -F 12345),但 - F 抓取信息会丢失部分信息,优先不用。

✅一个进程里面包含多个线程。进程是资源容器,线程是 CPU 调度的最小单位。

场景 1:线上 CPU 飙升,定位哪段代码占用 CPU

完整排查流程:

  1. top找到java进程PID=12345
  2. top -H -p 12345查看进程内线程,找到 CPU 最高线程号,假设线程号23456(十进制)
  3. jstack 12345 > thread.log导出线程栈日志
  4. 十进制转十六进制:printf "%x\n" 23456→ 0x5ba0=nid
  5. 在 thread.log 搜索nid=0x5ba0,找到对应线程栈,定位代码行
  • -p 12345:只监控 PID=12345 这个进程
  • -H:开启线程模式,把进程内部所有线程展示出来(top 默认只展示进程,不展开线程)

场景 2:排查死锁

jstack -l 12345 > deadlock.log

jstack 会自动检测死锁,日志末尾会输出Found one Java-level deadlock,打印两个线程互相等待的锁和代码位置。

示例死锁片段:

Found one Java-level deadlock: ============================= "Thread-A": waiting to lock monitor 0x00007f8b1c003210 (object 0x000000076ac21498, a java.lang.Object), which is held by "Thread-B" "Thread-B": waiting to lock monitor 0x00007f8b1c003320 (object 0x000000076ac214a8, a java.lang.Object), which is held by "Thread-A"

场景 3:接口响应缓慢,大量线程 WAITING/BLOCKED

jstack 12345 > stack.log

看线程状态:

  • BLOCKED:被锁阻塞
  • WAITING:等待唤醒(lock.wait () / 线程池队列等待)
  • TIMED_WAITING:限时等待(sleep)
  • RUNNABLE:运行中(IO 阻塞也会显示 RUNNABLE)

常见坑:大量线程卡在数据库连接池等待,就是大量 WAITING。

三、jmap:内存映像工具,堆内存分析(OOM、内存泄漏)

全称:Java Memory Map,JDK 自带堆内存分析工具。

核心能力:查看堆配置、查看当前堆使用情况、dump 堆快照文件,

用于分析OOM、内存泄漏。

语法:

jmap [option] <pid>

常用 option

  1. jmap -heap <pid>:打印堆配置与当前堆概览(快速看堆参数)
  2. jmap -histo[:live] <pid>:查看堆内对象统计(对象数量、占用大小)
    • histo:所有对象;histo:live只统计存活对象(会触发 FullGC)
  3. jmap -dump:format=b,file=heap.hprof <pid>:导出 hprof 堆快照文件(核心!)

⚠️ dump 堆文件会暂停应用,生产尽量业务低峰操作;hprof 文件建议下载本地,用 MAT(Memory Analyzer Tool)分析。

场景 1:快速查看 JVM 堆配置(Xmx/Xms/ 新生代比例)

jmap -heap 12345

输出:堆最大最小,Eden、Survivor、Old 大小,垃圾收集器类型。

场景 2:查看堆中对象数量,初步判断内存泄漏

jmap -histo:live 12345 > histo.log

输出按占用内存排序:

num instances bytes class name 1 1200000 48000000 java.util.ArrayList 2 800000 32000000 com.xxx.entity.User

如果自定义实体类数量持续暴涨,大概率内存泄漏。

场景 3:OOM 发生,导出堆快照(最常用)

jmap -dump:format=b,file=heap_20261008.hprof 12345

拿到heap_20261008.hprof文件,下载到本地,用 MAT 工具打开:

  • 看大对象
  • 看对象引用链,找出是谁持有对象没有释放

推荐:JVM 启动参数增加-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/xxx/,OOM 时自动 dump 堆文件,不用手动执行 jmap。

不推荐场景:生产不要频繁执行jmap -histo:live

因为加了:live会触发 FullGC,线上业务会卡顿。


四、三个工具对比总结

命令关注点适用场景
jstatGC 指标、类加载、JIT持续监控 GC,判断是否有 GC 异常
jstack线程栈、锁、线程状态CPU 高、死锁、接口 hang、线程阻塞
jmap堆内存、对象、堆 dumpOOM、内存泄漏,分析对象占用

五、一套完整线上故障排查流程示例

现象:服务接口变慢,时不时 OOM,老年代持续上涨

  1. jps -l获取 pid
  2. jstat -gcutil pid 1000观察,发现 Old 不断上涨,FGC 越来越多
  3. jstack pid查看是否有线程泄漏、连接不释放
  4. jmap -histo pid看到自定义业务对象数量持续暴涨
  5. jmap -dump:format=b,file=heap.hprof pid导出堆文件
  6. MAT 分析 hprof,找到对象引用链定位代码泄漏点

六、扩展

Q1:jstat -gcutil 各个字段含义?FGC 持续上涨代表什么?

答:

S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
  • S0:Survivor0 使用率;S1:Survivor1 使用率
  • E:Eden 区使用率;O:老年代使用率
  • M:元空间 Metaspace 使用率;CCS:压缩类空间使用率
  • YGC:年轻代 GC 次数;YGCT:YGC 总耗时
  • FGC:FullGC 次数;FGCT:FullGC 总耗时
  • GCT:GC 总耗时

FGC 持续上涨分两种情况:

  1. 每次 FGC 后 Old 能明显下降:正常业务,短期大对象,可观察;
  2. 每次 FGC 后 Old 下降很少,很快又涨满:内存泄漏,对象无法回收,需要 jmap dump 堆分析。

面试加分:FGC 非常耗时间,会 STW,频繁 FGC 会造成接口超时、服务卡顿。

Q2:jstack 怎么排查 CPU100%?完整步骤

答:

  1. top找到 Java 进程 PID;
  2. top -H -p pid查看进程内所有线程,找到 CPU 最高的十进制线程 id;
  3. printf "%x\n 线程id"转为十六进制 nid;
  4. jstack pid > thread.log导出线程栈;
  5. 在日志搜索nid=0x十六进制值,定位到对应线程栈,找到阻塞 / 死循环代码。

注意:jstack 输出里的 nid 是十六进制,top 看到的线程号是十进制,很多人这里踩坑。

Q3:jstack 看到大量 BLOCKED、WAITING 分别是什么含义?

答:

  • BLOCKED:线程正在等待监视器锁(synchronized),拿不到锁被阻塞;大概率锁竞争激烈、死锁;
  • WAITING:无限等待,等待被其他线程唤醒,如Object.wait()、LockSupport.park();常见:线程池无任务、数据库连接池拿不到连接;
  • TIMED_WAITING:限时等待,Thread.sleep()、wait(time);
  • RUNNABLE:运行中;注意:网络 IO 阻塞时,线程状态依然是 RUNNABLE,这点很容易答错。

Q4:jmap -histo 和 jmap -histo:live 的区别?生产慎用哪个?为什么?

答:

  • jmap -histo pid:打印堆中所有对象统计,不触发 FullGC;
  • jmap -histo:live pid:只统计存活对象,执行前会触发一次 FullGC。

生产慎用:histo:live,因为 FullGC 会 STW,业务请求卡顿,高峰期可能雪崩。

Q5:jmap dump 堆快照有什么风险?生产什么时候 dump?

答:风险:

  1. dump 过程会STW(暂停应用);
  2. hprof 文件大小接近堆最大值,占用大量磁盘 IO;
  3. 堆越大,dump 耗时越长。

最佳实践:

  1. 低峰期 dump;
  2. 优先配置 JVM 参数:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp,OOM 时自动 dump,不需要人工执行 jmap;
  3. 拿到 hprof 下载到本地,用 MAT 分析,不要在线上直接分析。

Q6:jstat、jstack、jmap 三者分工,故障排查时使用顺序?

答:

  • jstat:宏观监控,看 GC 指标,先判断有没有内存 / GC 问题;
  • jstack:线程层面,查 CPU 高、死锁、接口 hang;
  • jmap:内存对象层面,OOM、内存泄漏,dump 堆快照。

排查顺序:jps→jstat(确认 GC 异常)→jstack(看线程是否阻塞)→jmap(导出堆,定位泄漏对象)

Q7:jstack -F 参数作用?缺点?

答:jstack pid正常抓取;当进程卡死,正常 jstack 无法响应时,使用jstack -F pid强制 dump。 缺点:强制抓取会丢失部分信息,丢失 Java 锁信息,优先不用。

Q8:容器环境使用这些命令有什么坑?

答:容器内 Java 进程 PID 是容器内 PID,宿主机看不到; 解决:启动容器添加--pid=host,共享宿主机 pid 命名空间; 另外注意:JDK 镜像,必须装 JDK,不能只用 JRE(缺少 jstat/jstack/jmap 工具)。

Q9:OOM 一定是内存泄漏吗?

答:不一定。

  1. 内存泄漏:对象不再使用,但是一直被引用,GC 无法回收,Old 持续上涨;
  2. 非泄漏 OOM:一次性加载超大文件 / 大查询,瞬间分配对象超过堆上限;堆配置太小。

可以通过 jstat 观察区分:泄漏是缓慢持续涨老年代;大对象是瞬间把 Old 打满。

Q10:jstat 可以看线程堆栈吗?jstack 能看 GC 指标吗?

答:都不行。 jstat:只输出统计指标,看不到代码堆栈; jstack:只打印线程栈,不统计 GC、内存占用; 各司其职。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 12:12:45

PyCharm Python解释器与项目结构配置避坑指南

简介&#xff1a;这是一份面向Python初学者的PyCharm集成开发环境入门教程&#xff0c;聚焦开发前必备操作与高频使用场景&#xff0c;解决新手安装后不知如何创建项目、运行代码、识别错误及安装第三方库等实际问题。资源为单文件PDF文档&#xff08;492KB&#xff09;&#x…

作者头像 李华
网站建设 2026/10/19 17:34:48

Oracle EBS成批分配核心逻辑与静默故障排查指南

简介&#xff1a;本资源是一份面向Oracle EBS财务模块实施顾问、系统管理员及进阶财务用户的深度操作指南&#xff0c;聚焦ERP系统中关键的成批分配&#xff08;Batch Allocation&#xff09;功能&#xff0c;解决多成本中心、跨部门/公司间自动化分摊收入与费用的实务难题。文…

作者头像 李华
网站建设 2026/10/16 8:07:58

手写C++ RMDB内核:支持TPC-C压测的课程级数据库系统

简介&#xff1a;本资源是全国大学生计算机系统能力大赛数据库管理系统赛道的参赛项目成果&#xff0c;面向系统能力培养阶段的高校本科生与数据库内核学习者&#xff0c;聚焦关系型数据库管理系统&#xff08;RDBMS&#xff09;从零实现的核心技术实践。项目基于RMDB框架构建完…

作者头像 李华
网站建设 2026/10/19 20:07:51

SQL Server 2000 SP4个人版安装与运维:从环境准备到数据迁移

简介&#xff1a;SQL Server 2000 SP4个人版安装程序包&#xff0c;是微软经典关系型数据库管理系统的个人版安装介质&#xff0c;集成了SP4累积补丁与安全更新&#xff0c;面向需要在旧版Windows环境部署单机或小团队数据库的学习者、开发者和运维人员。整个RAR压缩包约378.59…

作者头像 李华
网站建设 2026/10/22 11:55:03

WordPress固定链接与伪静态404排查:文章URL结构完全指南

说实话&#xff0c;WordPress装好之后很多人第一件事就是闷头写文章、调主题&#xff0c;很少有人会认真看一眼后台"设置 → 固定链接"那个页面。直到某天你把文章链接发给朋友&#xff0c;发现地址栏里躺着一串/?p123&#xff0c;才意识到事情不对劲。链接结构这件…

作者头像 李华