VisualVM是功能最强大的虚拟机运行监视和故障处理程序之一,曾经在很长一段时间内是Oracle官方助理发展的虚拟机故障处理工具。
VisualVM的性能分析功能,比起JProfiler等专业收费工具也不遑多让,相比于第三方的功能,VisualVM还有一个很大的优点:不需要被监视的程序基于特殊的Agent去运行,因此它的通用性很强,对应用程序实际性能影响也比较小,使得它可以直接应用于生产环境。在这个注重颜值的时代,相较于JProfiler,可能界面比较丑陋是最大的缺点了吧。
在强大的插件加持下,VisualVM可以实现包括但不限于以下的功能:
- 显示虚拟机进程以及进程的配置、环境信息
- 显示应用程序的处理器、垃圾收集、堆、方法区及线程信息
- dump以及分析堆转储快照
- 方法级的应用程序性能分析,找出被调用最多、运行时间最长的方法
壹、安装插件
VisualVM插件可以直接在线安装,依次点击【tools】- 【plugins】
勾选需要安装的插件,点击【install】即可进行安装。
贰、生成、浏览堆转储快照
生成和浏览堆转储快照可能是日常开发过程中分析性能最常见的操作,下面介绍下在visualVM中如何生成或者分析堆转储快照。
一、生成堆转储快照
我们运行一个程序后,在visualVM左侧Local下,会自动加载对应的进程信息。
比如我这里的JHSDB_TestCae
,我们下面都以这个为例进行说明。
可以通过以下两种方式之一生成堆转储快照
- 选择应用程序,点击右键,然后选择【Heap Dump】
- 双击应用程序,在打开的页面中,选择【Monitor】,然后选择【Heap Dump】
快照存储后会自动打开。
二、打开堆转储快照
如果是别人发过来的快照文件,可以点击左上角的文件图标打开。
Overview
页签显示的是一些基本信息,包括pid
、Java版本、虚拟机参数、环境参数等信息。
Monitor
页签是图标信息显示的CPU、堆、元空间、类及线程等信息。
Threads
页签显示的是线程信息
Sampler
页签以一定的时间间隔对CPU、内存进行采样,可检查出占用CPU时间较多或占用内存空间较大的线程,有助于性能调优。对CPU采样时,该页提供CPU样例(CPU samples)和线程CPU时间(Thread CPU time)两个子页签,前者可用于分析调用链上的方法耗时,后者可用于比较线程CPU耗时。
profiler
是性能分析页签,因为性能分析对程序运行性能影响较大,生产环境不建议使用。
叁、常见插件介绍
上面所过,VisualVM是支持插件的,下面我们介绍几款常用的插件。
一、BTrace动态日志跟踪
BTrace允许在不中断目标程序的前提下,通过HotSpot虚拟机的Instrument功能动态加入原本并不存在的调试代码。
在插件页面,选择BTrace Workbench,然后安装
我们创建一段输出固定内容的死循环并运行
package cc.lisen.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* description:
*
* @author: lisen
* @Blog:<a href="https://lisen.cc">lisen.cc</a>
* @DateTime: 2025-04-20 20:34
*/
public class BTraceTest {
public String sayHello(String name) {
return "Hello " + name;
}
public static void main(String[] args) throws IOException {
while (true) {
BTraceTest bTraceTest = new BTraceTest();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println(bTraceTest.sayHello(reader.readLine()));
}
}
}
打开VisualVM,找到我们的程序,点击右键
选择【Trace Application】,然后输入以下脚本
/* BTrace Script Template */
import org.openjdk.btrace.core.annotations.*;
import static org.openjdk.btrace.core.BTraceUtils.*;
@BTrace(unsafe=true)
public class TracingScript {
@OnMethod(
clazz="cc.lisen.test.BTraceTest",
method="sayHello",
location=@Location(Kind.RETURN)
)
public static void func(@Self cc.lisen.test.BTraceTest instance,String test,@Return String result)
{
System.out.println("调用堆栈:");
jstack();
}
}
评论 (0)