VisualVM 使用教程:全方位解析 Java 性能分析利器
目录
- 什么是 VisualVM?
- 如何安装与启动 VisualVM?
- 连接到目标 JVM
- 核心功能详解
- 1 概览
- 2 监控
- 3 线程
- 4 抽样器
- 5 MBeans (管理 Bean)
- 6 快照
- 高级功能
- 1 远程监控
- 2 BTrace 动态追踪
- 3 插件扩展
- 实战演练:排查一个 CPU 100% 的问题
- 总结与最佳实践
什么是 VisualVM?
VisualVM 是一个功能强大的、免费的 Java 虚拟机监控、故障排查和性能分析工具,它作为 JDK 的一部分(从 JDK 6 Update 7 开始)被自带,无需额外安装,是每个 Java 开发者都应该掌握的“瑞士军刀”。

主要功能:
- 本地和远程监控:可以监控本地或远程的 Java 应用程序。
- 实时性能数据:实时查看 CPU、堆内存、线程、类加载等关键指标。
- 内存分析:查看堆内存的详细使用情况,分析内存泄漏。
- 线程分析:查看线程状态、死锁,分析线程阻塞问题。
- CPU 性能分析:通过抽样或追踪方式,分析方法级的 CPU 执行时间,找到性能瓶颈。
- 垃圾回收分析:监控 GC 的频率和耗时。
- 快照功能:可以保存应用的当前状态(内存、线程等快照)以便后续分析。
- BTrace 集成:可以在不重启应用的情况下,动态地执行诊断脚本。
如何安装与启动 VisualVM?
VisualVM 通常已经包含在你的 JDK 安装目录中。
安装
- 确保 JDK 已安装:VisualVM 依赖于 JDK,请确保你的系统已安装 JDK。
- 找到 VisualVM:它位于 JDK 的
bin目录下。- Windows:
C:\Program Files\Java\jdk-<version>\bin\visualvm.exe - macOS/Linux:
/Library/Java/JavaVirtualMachines/jdk-<version>/Contents/Home/bin/visualvm或/usr/lib/jvm/jdk-<version>/bin/visualvm
- Windows:
- 启动:
- Windows: 双击
visualvm.exe。 - macOS/Linux: 在终端中执行
chmod +x visualvm然后运行./visualvm。
- Windows: 双击
启动后的界面
启动后,你会看到 VisualVM 的主界面,左侧是“本地”和“远程”两个标签页。
连接到目标 JVM
VisualVM 默认会自动扫描并显示本地所有正在运行的 Java 进程,你只需要在左侧列表中点击你想要监控的应用程序即可。

连接到远程 JVM
如果你想监控另一台服务器上的 Java 应用,需要进行简单配置:
-
在远程服务器上启动 JVM 时添加参数: 你需要让 JVM 开启 JMX (Java Management Extensions) 远程监控端口。
java -Dcom.sun.management.jmxremote.port=<port> \ -Dcom.sun.management.jmxremote.authenticate=false \ -Dcom.sun.management.jmxremote.ssl=false \ -jar your-application.jar-Dcom.sun.management.jmxremote.port=<port>: 指定 JMX 监控的端口号,9999。-Dcom.sun.management.jmxremote.authenticate=false: 关闭认证(生产环境请务必开启)。-Dcom.sun.management.jmxremote.ssl=false: 关闭 SSL(生产环境请务必开启)。
-
在 VisualVM 中添加远程主机:
- 在左侧的“远程”标签页,右键点击。
- 选择“添加远程主机...”。
- 输入远程服务器的 IP 地址或主机名,点击“确定”。
- 连接成功后,展开该主机,你就能看到服务器上所有开启了 JMX 的 Java 进程了。
核心功能详解
选择一个本地或远程的 Java 进程后,VisualVM 的主界面会显示该应用的详细信息。

1 概览
这是最基础的信息页,展示了应用的概要信息。
- 监视器: 实时折线图,展示:
- 堆内存使用情况:
Eden,Survivor,Old(Tenured) 区的使用量,当内存持续增长且不下降时,可能预示着内存泄漏。 - CPU 使用率:应用的 CPU 占用百分比。
- 类加载器:已加载和卸载的类数量。
- 线程数:活动线程和守护线程的数量。
- 堆内存使用情况:
- 摘要:
- 基本属性:主类、JVM 参数、PID 等。
- 性能:总 CPU 时间、总采样时间等。
- 内存:堆/非堆内存总量、已用、最大值等。
2 监控
这个标签页与“概览”中的监视器功能类似,但提供了更详细的实时图表,可以让你更直观地观察性能趋势。
3 线程
这个标签页是排查线程问题的利器,如死锁、高负载、线程阻塞等。
- 线程状态饼图:直观展示所有线程处于不同状态(
RUNNABLE,WAITING,TIMED_WAITING,BLOCKED,TERMINATED)的占比。 - 线程列表:
- 线程名称:线程的名称。
- 状态:线程的当前状态。
- CPU 时间:线程消耗的总 CPU 时间。排序这个列可以快速找到最消耗 CPU 的线程。
- 监视器:线程等待的锁对象。
- 死锁检测:如果检测到死锁,VisualVM 会明确提示,并展示死锁线程的堆栈信息,帮助你快速定位问题。
4 抽样器
这是 VisualVM 最强大的功能之一,用于分析 CPU 和内存的使用情况。
CPU 抽样
CPU 抽样器通过周期性地(默认是 10ms)对所有线程的堆栈进行采样,统计每个方法被采样的次数,从而估算出方法的执行时间占比。
使用场景:查找应用的性能瓶颈,即哪个方法最耗时。
使用步骤:
- 点击“CPU”标签页。
- 点击“开始”按钮开始抽样。
- 在应用中复现你想要分析的性能问题(让应用处理一个请求)。
- 点击“停止”按钮结束抽样。
- 查看结果:
- 线程:可以按线程查看,找到哪个线程最忙。
- 类:可以按类查看,找到哪个类消耗最多 CPU。
- 方法:可以按方法查看,这是最核心的视图,它会列出所有被采样到的方法,并按调用次数排序,排在最顶端的,就是最耗时的方法,你的性能瓶颈通常就在这里。
内存抽样
内存抽样器用于分析内存分配情况,帮助定位内存泄漏点。
使用场景:怀疑应用有内存泄漏,内存持续增长。
使用步骤:
- 点击“内存”标签页。
- 点击“开始”按钮开始抽样。
- 在应用中复现内存泄漏的场景(反复执行某个操作)。
- 点击“停止”按钮。
- 查看结果:
- 类:视图会列出所有被实例化的类,并按实例数量排序,如果一个类的实例数量在操作后持续增长且没有下降,那么这个类很可能就是内存泄漏的源头。
- 查看实例:选中可疑的类,右键点击,选择“查看实例”,可以查看具体的对象内容,帮助你分析为什么这个对象没有被回收。
5 MBeans (管理 Bean)
MBeans 是 JVM 和应用内部管理信息的标准接口,通过这个标签页,你可以深入查看和管理应用的内部状态。
- 查看 JVM 信息:在
com.sun.management下,可以找到 HotSpotDiagnosticMXBean,可以用来执行 GC、生成堆转储文件等。 - 查看应用自定义 MBean:如果你的应用实现了自己的 MBean,也可以在这里看到和操作。
6 快照
快照功能可以保存应用在某一时刻的完整状态,方便后续分析或与他人分享。
- 应用程序快照:保存应用的概览、监视器、线程等信息。
- 堆转储:极其重要,保存当前堆内存中所有对象的快照,这是分析内存泄漏最直接、最强大的方式。
- 如何生成:在“监视器”或“页面,点击“堆 Dump”按钮。
- 如何分析:生成的堆转储文件(.hprof)可以在 VisualVM 中打开,或者在更专业的工具如 Eclipse MAT 中打开进行分析,分析时会告诉你哪些对象占用了最多内存,以及它们是通过怎样的引用链被根对象(如静态变量、线程等)持有的。
高级功能
1 远程监控
除了上面提到的 JMX 方式,VisualVM 还支持通过 jstatd 进行更轻量级的远程监控。
- 在远程服务器上启动 jstatd:
# 在 JDK bin 目录下执行 ./jstatd -J-Djava.security.policy=all.policy
all.policy是一个策略文件,内容如下:grant codebase "file:${java.home}/../lib/tools.jar" { permission java.security.AllPermission; }; - 在 VisualVM 中添加:在“远程”标签页,右键选择“添加 Jstatd 连接...”,输入服务器地址即可。
注意:jstatd 功能有限,且安全性较低,生产环境推荐使用 JMX。
2 BTrace 动态追踪
BTrace 是一个强大的动态追踪工具,它允许你在不停止、不重启目标应用的情况下,动态地向其注入 Java 代码来收集诊断信息。
使用场景:
- 打印某个特定方法的入参和返回值。
- 统计某个方法的调用次数和平均耗时。
- 打印某个异常的完整调用堆栈。
使用步骤:
- 在 VisualVM 中安装 BTrace 插件:工具 -> 插件 -> 可用插件 -> 搜索并安装 "BTrace Workbench"。
- 选中你的应用,点击右键,选择 "Trace Application"。
- 在弹出的 BTrace 编辑器中,编写 BTrace 脚本。
- 点击 "Start" 运行脚本,脚本会在后台持续执行,并将输出打印到 BTrace 控制台。
示例脚本 (打印 java.io.File 构造函数的调用)
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class TraceConstructor {
// @OnMethod 注解用于拦截方法
// @Self 表示拦截的是实例方法,self 代表实例对象
@OnMethod(
clazz="java.io.File",
method="<init>"
)
public static void traceConstructor(@Self Object self, String path) {
// 打印构造函数的调用信息
println("File constructor called with path: " + str(path));
// 可以打印调用堆栈
jstack();
}
}
3 插件扩展
VisualVM 的功能可以通过插件极大地增强,最著名的插件是:
- VisualVM插件中心:在 VisualVM 的
工具 -> 插件 -> 可用插件中,可以搜索和安装各种插件。 - GCViewer:集成 VisualVM,用于可视化分析 GC 日志文件。
- MBeans:增强 MBeans 的查看功能。
- Sampler:增强性能分析功能。
实战演练:排查一个 CPU 100% 的问题
假设你有一个在线服务,某时刻 CPU 使用率突然飙到 100%,响应变得非常缓慢。
- 启动 VisualVM,连接到该 Java 进程。
- 观察“概览”或“监控”标签页,确认 CPU 使用率确实持续 100%。
- 切换到“线程”标签页,按“CPU 时间”列排序,你会看到一个或多个线程占用了绝大部分 CPU 时间,记下这个线程的 ID 和名称。
- 切换到“抽样器” -> “CPU”标签页,点击“开始”。
- 等待几十秒,让抽样器收集足够的数据。
- 点击“停止”。
- 在抽样结果中,按“方法”排序,查看调用次数最多的方法。
- 分析结果:你很可能会看到一个业务方法(
com.your.service.Calculator.calculate())排在最前面,并且它的调用占比非常高(95%)。 - 定位问题:现在你已经知道问题出在
Calculator.calculate()方法,你可以:- 查看该方法的源代码,看是否有死循环、低效的算法(如 O(n²) 的排序)。
- 检查是否有不必要的对象创建,导致频繁 GC,但在这个场景下,CPU 100% 通常是计算密集型问题。
- 修复代码:优化算法或修复逻辑,重新部署应用。
总结与最佳实践
- VisualVM 是你的第一道防线:对于大多数本地和简单的远程问题,VisualVM 已经足够强大和便捷。
- 定期观察:在应用上线后,可以使用 VisualVM 定期观察其运行状态,建立基线,以便在异常时快速对比。
- 善用快照:遇到疑难杂症时,不要犹豫,立即生成一个堆转储快照,这是离线分析的关键。
- CPU 和内存分析要分清:
- CPU 高:用 CPU 抽样器 找出最耗时的方法。
- 内存高/泄漏:用 内存抽样器 或 堆转储 找出无法被回收的对象。
- BTrace 是神器:对于偶发性、难以复现的问题,BTrace 可以在不影响服务的情况下动态获取信息,是生产环境的必备技能。
- 它不是万能的:对于超大规模、高并发的应用,VisualVM 可能会成为性能瓶颈,此时应考虑使用更专业的工具,如 JProfiler, YourKit, Arthas (国产神器,更轻量,支持命令行) 或 Prometheus + Grafana 等监控体系。
希望这份详细的教程能帮助你掌握 VisualVM,让它成为你排查 Java 问题时的得力助手!
