当前位置: 首页 > news >正文

全面解析 JDK 提供的 JVM 诊断与故障处理工具

1. 引言:为什么需要 JVM 诊断工具?

在现代 Java 应用中,JVM(Java Virtual Machine)是承载所有 Java 程序运行的核心平台。它不仅负责类加载、内存分配、垃圾回收、线程调度等关键功能,还决定了程序的性能和稳定性。一旦 JVM 出现问题,如内存泄漏、线程死锁、GC 频繁、类加载失败等,将直接影响业务系统的可用性。

然而,JVM 是一个高度封装和自动化的黑盒系统,绝大多数运行时行为在默认情况下对开发者不可见。这就迫切需要一系列专业工具,帮助我们在运行时“窥视”JVM 的内部状态,进行排障和性能调优。

1.1 典型问题场景

以下是一些典型的问题场景,每一种都需要不同的工具协同解决:

  • 内存泄漏 / 内存溢出(OutOfMemoryError):使用 jmap 导出堆快照,结合 jhat 或 VisualVM 分析。

  • 频繁 Full GC 或 GC 时间过长:使用 jstatjcmdvisualgc 观察 GC 行为,调优 JVM 参数。

  • 线程死锁 / 卡顿:使用 jstack 获取线程堆栈,结合代码定位死锁点。

  • 应用启动参数或环境不一致:使用 jinfo 查看运行时参数和系统属性。

  • JVM 崩溃或 core dump:通过 hsdbjhsdb 分析 JVM 崩溃现场。

1.2 JVM 工具的重要性

JVM 诊断工具不仅在紧急问题排查中发挥关键作用,也在日常调优、回归验证、环境对比等方面具备重要价值。尤其是在大型微服务集群、多版本 JDK 混用、远程部署等复杂场景下,工具的可操作性和准确性成为保障系统稳定性的关键。

此外,随着 JDK 的不断演进(如 JDK 21+),部分传统工具逐步被 jcmd 统一整合,部分新功能(如 Flight Recorder、HeapDumpOnOutOfMemory)也提供了更强的观测能力。了解工具的历史沿革与现代替代方案,有助于在实际工作中选取最合适的方案。

1.3 本文目标与结构

本博客将系统介绍 JDK 提供的各类 JVM 诊断工具,重点聚焦如下几个方面:

  • 每个工具的原理、用法、命令格式与示例

  • 常见问题如何使用工具组合排查

  • JDK 21 及以后版本的工具变化与新增功能

  • 工具的优劣分析及使用建议

希望通过这篇文章,帮助开发者掌握 JVM 运行时分析的核心技能,提升故障处理效率,构建更高质量、更稳定的 Java 应用系统。


2. jps:JVM 进程状态工具

2.1 工具简介

jps(Java Virtual Machine Process Status Tool)是 JDK 提供的轻量级命令行工具,用于列出本地或远程主机上所有正在运行的 Java 进程及其相关信息。它的作用类似于操作系统的 ps 命令,但专门服务于 JVM 进程。

在使用如 jstackjmapjcmd 等高级工具前,首先要定位 Java 进程的 PID,而 jps 正是首选手段。


2.2 命令格式与参数说明

jps [options] [hostid]

常用参数:

  • -l:输出主类的全名或 jar 文件完整路径

  • -v:输出传递给 JVM 的启动参数

  • -m:输出传递给 main 方法的参数

  • -q:仅显示进程 PID,不显示类名

示例:

jps -lv

2.3 使用示例与输出解析

示例一:列出所有本地 JVM 进程

$ jps
31584 Jps
31122 MySpringBootApp
30001 Kafka
29999 JConsole
  • 第一列是 PID

  • 第二列是主类名或 jar 包名

示例二:带参数查看类路径和 JVM 参数

$ jps -lv
31122 com.example.Main -Xms512m -Xmx1024m -Dspring.profiles.active=prod

示例三:仅列出 PID(适合脚本场景)

$ jps -q
31122
31584

2.4 典型用法示例

# 找到目标进程 PID 后,获取线程堆栈信息
jstack 31122 > thread_dump.txt
# 查看当前用户可见 JVM 列表,确认特定程序是否已启动
jps -l | grep MyApp

2.5 注意事项

  • jps 只能列出当前用户权限下可见的 JVM 进程,必要时加 sudo 扩展权限

  • 某些精简版 JDK(如 Alpine Linux)可能缺少 jps,需要安装完整 JDK

  • 如果提示 Could not find or load main class sun.tools.jps.Jps,说明 JDK 安装不完整或环境变量配置有误


2.6 常见应用场景

  • 快速确认 Java 应用是否在运行

  • 多进程环境下快速获取目标进程 PID

  • jmapjstackjcmd 等工具协作使用

  • 结合脚本或监控工具自动化诊断


 

3. jstat:JVM 统计信息监控工具

3.1 工具用途及核心原理

jstat(JVM Statistics Monitoring Tool)是 JDK 提供的用于实时监控 JVM 各种运行时统计信息的命令行工具。它可以帮助开发者分析 GC 行为、类装载、JIT 编译等运行状况,对于诊断内存问题和性能瓶颈至关重要。

核心原理基于 HotSpot 内部的性能计数器(Performance Counter),通过 VM attach 接口获取当前进程的状态信息,而不需额外侵入应用逻辑或重启服务。


3.2 命令格式与参数说明

jstat [option] <vmid> [interval] [count]
  • option:监控类型(如 gcclass 等)

  • vmid:Java 进程 ID,可通过 jps 获取

  • interval(可选):刷新间隔(毫秒)

  • count(可选):输出次数


常用 option 参数说明:

参数说明
class类装载、卸载数量
compilerJIT 编译信息
gc垃圾回收概览统计
gccapacity每块内存区域容量信息
gcutil各内存区域使用率
printcompilation方法编译情况

 


3.3 使用示例与输出解析

示例一:查看 GC 活动

jstat -gc 31122 1000 5

每隔 1 秒采样一次,共输出 5 次,结果如:

S0C    S1C    S0U    S1U      EC       EU        OC         OU        MC       MU      CCSC     CCSU       YGC     YGCT       FGC    FGCT     GCT
1024.0 1024.0  0.0    8.5   8192.0   2560.0    32768.0    16384.0    4480.0   4212.3    512.0     487.6       5      0.045      1     0.032    0.077

字段解析:

  • S0C/S0U:Survivor 0 区容量 / 使用量

  • EC/EU:Eden 区容量 / 使用量

  • OC/OU:Old 区容量 / 使用量

  • YGC/YGCT:年轻代 GC 次数 / 耗时

  • FGC/FGCT:Full GC 次数 / 耗时

  • GCT:GC 总耗时


示例二:类加载信息监控

jstat -class 31122 2000

输出:

Loaded Bytes Unloaded Bytes Time 5123 5.8M 12 150K 32.55

表示当前加载类数、卸载类数及耗时。


示例三:GC 使用率可视化数据

jstat -gcutil 31122 1000 3

输出类似:

S0     S1     E      O      M     CCS    YGC   YGCT    FGC   FGCT     GCT
12.00   0.00  32.35  50.67  94.44  78.91     7   0.121     2   0.046    0.167

可以看到各区使用百分比与 GC 次数、总耗时等。


3.4 注意事项

  • jstat 仅支持 HotSpot JVM,不支持 GraalVM。

  • 某些进程(特别是容器内部)需配置 -XX:+PerfDisableSharedMem 以防性能监控信息无法采集。

  • 不适用于挂死或核心 dump 的 JVM,可结合 jcmd 补充数据。


3.5 应用场景总结

  • 分析 GC 活动是否频繁

  • 查看老年代回收时间是否过长

  • 监控类加载增长是否异常

  • 用于自动化脚本、监控平台对接


 

4. jinfo:JVM 配置信息查询工具

4.1 工具介绍

jinfo(Java Configuration Info Tool)是用于在运行时获取 Java 应用配置信息的工具,包括启动参数(如 -Xmx)、系统属性(-D 选项)以及 JVM 运行时环境设置。

它适用于调试配置项是否生效、比对多环境 JVM 参数差异、验证线上服务启动参数等场景。

在某些平台上(如 Java 11+),jinfo 被逐步弱化,推荐使用 jcmd VM.flagsjcmd VM.system_properties 等子命令替代。

4.2 命令格式与参数说明

jinfo [option] <pid>

常用选项说明:

  • <pid>:目标 Java 进程的 PID

  • -flags:显示 JVM 启动参数(包括默认、已显式设定和命令行)

  • -sysprops:显示系统属性(等价于 System.getProperties()

  • -flag [+|-]name:动态开启或关闭布尔型参数(部分参数支持)

4.3 使用示例与输出说明

示例一:查看 JVM 启动参数

jinfo -flags 31122

输出示例:

-XX:InitialHeapSize=268435456
-XX:+PrintGC
-XX:MaxHeapSize=4294967296

其中:

  • = 后是对应的数值参数

  • + 表示布尔参数启用,- 表示未启用

示例二:查看系统属性

jinfo -sysprops 31122

输出示例:

java.runtime.name=Java(TM) SE Runtime Environment
java.vm.version=25.281-b09
file.encoding=UTF-8
user.timezone=Asia/Shanghai

示例三:修改 JVM 参数(实验性)

某些参数可在运行时修改,例如:

jinfo -flag +PrintGC 31122

注意:此功能依赖 JVM 是否支持在线修改,很多商用 JVM 可能禁用。

4.4 注意事项

  • 从 JDK 9 开始,jinfo 在某些发行版中默认不再推荐使用,建议替代为 jcmd

  • 不支持远程进程(需运行在本机或使用 SSH 登录目标服务器)。

  • 某些参数即使修改成功,也不会立即生效,需重启应用。

4.5 应用场景总结

  • 确认 -Xmx、GC 选项、系统属性是否正确生效

  • 对比开发与生产环境参数差异

  • 结合 jstat 分析配置与运行状态是否一致

  • 替代代码方式输出 System.getProperties() 的值


 

5. jmap:内存映射工具

5.1 工具用途与内部机制

jmap(Java Memory Map)是 JDK 提供的用于查看和导出内存结构信息的命令行工具,主要用于:

  • 查看对象在堆中的分布情况(如各类实例数量和内存占用)

  • 导出堆快照(heap dump)文件,供后续分析工具使用(如 Eclipse MAT、VisualVM 等)

  • 查看特定内存区域的使用信息

其原理是通过 SA(Serviceability Agent) 连接目标 JVM 的内存空间,提取堆内结构。部分模式依赖 HotSpot 内部接口,因此仅在特定 JVM 实现中可用。


5.2 命令格式与参数说明

jmap [option] <pid>

常用参数选项:

参数说明
-heap显示 Java 堆概况,包括新生代/老年代大小与使用率
-histo[:live]显示堆中对象的统计(类型、数量、大小),加 :live 可只统计可达对象
-dump:live,format=b,file=<path>导出堆快照文件,仅包含可达对象
-dump:format=b,file=<path>导出所有对象(包括不可达)
-finalizerinfo显示 Finalizer 队列中待处理对象

提示:如在 jmap 输出中看到 Unable to open socket file 错误,说明目标进程权限不足或未启用诊断接口。


5.3 使用示例与输出说明

示例一:查看堆使用概况

jmap -heap 31122

输出内容包括:

  • 堆各区域(Eden、Survivor、Tenured)的总容量、使用大小

  • GC 相关策略(如 Parallel、CMS、G1)

  • GC 触发条件与堆增长策略

示例二:查看堆中对象的类型和数量

jmap -histo 31122 | head -n 20

输出示例:

 num     #instances         #bytes  class name
----------------------------------------------1:         53101       4673208  [C2:         12845       1953984  java.lang.String3:         23512       1880960  java.util.HashMap$Node

示例三:导出堆快照供分析工具使用

jmap -dump:live,format=b,file=/tmp/heapdump.hprof 31122

导出完成后,可使用如下工具打开:

  • Eclipse MAT(Memory Analyzer Tool)

  • VisualVM(带 Heap Dump 插件)

  • jhat(已弃用)


5.4 注意事项与限制

  • 权限问题:必须对目标 JVM 拥有操作系统层的访问权限,建议使用与应用相同的用户或加 sudo。

  • 性能影响:执行 -histo-dump 操作会 Stop The World,在生产环境中务必慎重。

  • 兼容性:部分参数在 JDK 9+ 后不再推荐,建议使用 jcmd GC.heap_infojcmd GC.class_histogram 作为替代。

  • 安全问题:某些容器环境(如 Docker)中需正确挂载 /proc 和 JVM 工具路径。


5.5 典型应用场景

  • 内存泄漏定位:使用 -dump 导出堆并配合 MAT 查看 GC Root 引用链。

  • 对象暴涨分析:通过 -histo 查看某类实例数量是否异常。

  • 对比启动后与运行中状态:定期采样、对比不同时间点堆的分布。


6. jhat:堆分析工具(已弃用) 

7. jstack:线程堆栈分析工具

7.1 工具用途简介

jstack 是用于打印指定 Java 进程中所有线程的栈信息(Stack Trace)的工具。它常用于分析:

  • 线程死锁(Deadlock)

  • 阻塞或卡顿线程

  • 热点线程状态(运行中、等待、睡眠)

  • 垃圾回收线程活动

其原理是通过 JVM TI(Tool Interface)与目标进程交互,输出当前线程的状态及调用栈信息。


7.2 命令格式与参数说明

jstack [option] <pid>

常见参数:

参数含义
-F强制模式(用于无响应进程)
-l输出扩展信息,如锁对象及栈上变量
-m显示 Java + 本地方法调用栈(混合模式)

7.3 示例与输出分析

示例一:查看所有线程栈

jstack 31122 > thread_dump.txt

输出中每个线程包含如下信息:

"main" #1 prio=5 os_prio=0 tid=0x0000000001d0f000 nid=0x7ac runnable [0x00000000029af000]java.lang.Thread.State: RUNNABLEat com.example.Test.main(Test.java:15)

字段说明:

  • 线程名称(如 "main")

  • tid/nid:JVM 和操作系统线程 ID

  • 状态:RUNNABLEWAITINGTIMED_WAITINGBLOCKED

  • 堆栈信息:调用路径,显示阻塞点

示例二:检测死锁

jstack -l 31122 | grep -A 20 "Found one Java-level deadlock"

若存在死锁,会出现如下内容:

Found one Java-level deadlock:
"Thread-1": waiting to lock monitor 0x00007fae9c0030a0 (object 0x000000076b0f2a78), which is held by "Thread-2"
"Thread-2": waiting to lock monitor 0x00007fae9c0030b8 (object 0x000000076b0f2a90), which is held by "Thread-1"

7.4 示例程序:模拟死锁进行分析

public class DeadlockDemo {private static final Object lockA = new Object();private static final Object lockB = new Object();public static void main(String[] args) {Thread t1 = new Thread(() -> {synchronized (lockA) {try { Thread.sleep(100); } catch (Exception ignored) {}synchronized (lockB) {System.out.println("Thread-1 完成");}}});Thread t2 = new Thread(() -> {synchronized (lockB) {try { Thread.sleep(100); } catch (Exception ignored) {}synchronized (lockA) {System.out.println("Thread-2 完成");}}});t1.start();t2.start();}
}

执行上述程序后使用 jstack 查看,会检测到死锁信息。


7.5 注意事项与实践建议

  • jstack 在 Linux 上必须使用与目标 JVM 相同的用户或 root 权限

  • 若目标进程无响应,使用 -F 强制输出

  • 多次采样(如每 10 秒输出一次)可更有效观察线程状态变化

  • 可结合 top -Hp <pid> 定位 CPU 占用高的线程,通过 nid 对应 jstack 中的线程信息


8. jcmd:现代通用诊断命令工具

8.1 工具概览与设计理念

jcmd(Java Command)是 Java 7 之后引入的统一诊断接口工具,旨在替代传统的 jmapjstackjinfo 等分散工具。通过向目标 JVM 发送特定命令,实现对内存、线程、GC、类加载等状态的实时观测和控制。

它具备以下特点:

  • 命令集合统一(如 GC.heap_infoThread.printVM.flags

  • 输出信息更丰富,格式更标准

  • 支持 JFR(Java Flight Recorder)等高级功能

  • 支持自定义命令扩展(从 JDK 11 起)


8.2 命令格式与基本用法

jcmd <pid | main-class> <command> [options]

如:

jcmd 31122 GC.heap_info

查看支持的命令列表:

jcmd 31122 help

输出示例:

31122:VM.versionGC.class_histogramGC.heap_infoThread.printVM.system_properties

8.3 常用子命令与示例

1. 查看堆信息(替代 jmap -heap)

jcmd 31122 GC.heap_info

输出包括:

  • 堆各区域的使用情况(Eden、Old、Survivor)

  • GC 实现名称(G1、ZGC、Shenandoah 等)

  • 垃圾收集策略与容量限制

2. 获取堆中对象统计信息(替代 jmap -histo)

jcmd 31122 GC.class_histogram

类似 jmap -histo,输出实例数、占用空间、类名等信息:

  num     #instances         #bytes  class name
----------------------------------------------1:         53101       4673208  [C2:         12845       1953984  java.lang.String

3. 打印所有线程的栈信息(替代 jstack)

jcmd 31122 Thread.print

4. 查看或修改 JVM 启动参数(替代 jinfo -flags)

jcmd 31122 VM.flags

5. 查看系统属性(等价于 System.getProperties)

jcmd 31122 VM.system_properties

6. 导出堆 Dump 文件(替代 jmap -dump)

jcmd 31122 GC.heap_dump /tmp/heapdump_31122.hprof

8.4 JDK 21+ 新增或推荐命令

在 JDK 21 中,jcmd 引入或推荐以下新命令:

  • JFR.configure / JFR.start / JFR.stop:管理 JFR 事件记录

  • VM.native_memory summary:内存占用快照(Native Memory Tracking)

  • Compiler.codecache:查看 JIT 编译缓存

  • GC.finalizer_info:输出 Finalizer 队列状态


8.5 注意事项与最佳实践

  • 推荐使用 jcmd help 获取当前进程可支持的完整命令列表

  • 与传统工具相比,jcmd 提供的信息更全面且格式标准

  • 某些命令如 GC.class_stats 需开启 -XX:+UnlockDiagnosticVMOptions

  • 在容器中使用时应确保 PID 与宿主机一致或使用 docker exec 进入容器内执行


8.6 应用场景总结

诊断任务推荐 jcmd 命令
堆内存使用GC.heap_info
对象实例统计GC.class_histogram
导出堆快照GC.heap_dump
打印线程栈Thread.print
查看参数VM.flags
查看系统属性VM.system_properties

 


 

 

http://www.lryc.cn/news/594345.html

相关文章:

  • Linux之dpkg--命令的用法
  • MySQL EXPLAIN 解读
  • linux shell从入门到精通(一)——为什么要学习Linux Shell
  • 【OD机试】池化资源共享
  • 小架构step系列20:请求和响应的扩展点
  • OPC UA, CAN, PROFINET, SOCKET, MODBUS, HTTP, S7七种物联网常用协议解释
  • 2.组合式API知识点(1)
  • 【并集查找 二分图】P6185 [NOI Online #1 提高组] 序列|省选-
  • JavaScript 对象操作、继承与模块化实现
  • 基于单片机的数字温度计设计
  • Ubuntu 部署 STUN 与 TURN 服务器
  • BLIP、InternVL Series(下)
  • 从TPACK到TPACK - AI:人工智能时代教师知识框架的重构与验证
  • 血条识别功能实现及原理
  • Mobile Neural Network (MNN) 3.2.1
  • CAN通讯理论与实践:调试和优化全讲解
  • EPLAN 电气制图(十): 继电器控制回路绘制(下)放料、放灰
  • UDP中的单播,多播,广播(代码实现)
  • 前端环境搭建---基于SpringBoot+MySQL+Vue+ElementUI+Mybatis前后端分离面向小白管理系统搭建
  • Linux场景常见的几种安装方式
  • VSCode使用Jupyter完整指南配置机器学习环境
  • 在服务器无网络的环境下安装 VS Code Remote-SSH 组件
  • (5)从零开发 Chrome 插件:Vue3 Chrome 插件待办事项应用
  • 数控调压BUCK电路 —— 基于TPS56637(TI)
  • Spring Cloud Gateway高危隐患
  • jmeter如何做自动化接口测试?
  • jQuery多库共存
  • http基础一
  • 游戏剧情抄袭侵权比对报告:防止“爆款”变“爆雷”
  • C 语言经典编程题实战:从基础算法到趣味问题全解析