Java性能工具汇总
从实现方式上,大致可以分为下面几类:
- 基于读取hsperfdata:jps,jstat,jstack、jcmd
- 基于JMX:VisualVM,JConsole
- 基于SA:VisualVM,JHsdb
- 基于JVMTI:async-profiler
- 基于Instrumentation:Arthas
- 基于JVM Internal:JFR
- 基于Sampling
JDK自带的工具
总览
在JDK的bin目录中,不仅存在javac,java这两个编译和运行Java程序的命令,还包含各种性能监控,故障处理的工具。这些工具大致可以分为三类:
- 商业授权工具
- 正式支持工具
- 实验性工具
基础性命令行工具
jps
jps(JVM Process Status)是一个最基础的工具,它的名字和Unix系统中的ps命令很相似.功能也很相似。它可以列出正在运行的虚拟机进程,并显示虚拟机执行主类名称(Main Class, main函数所在的类),以及这些进程的本地虚拟机唯一 ID(LVMID,Local Virtual Machine Identifier)。jps因为其功能的特殊性,绝对是使用频率最高的JKD命令行工具之一。
除此之外,jps还支持通过RMI协议查询开启了RMI服务的远程虚拟机进程状态,参数hostid为RMI注册表中注册的主机名。
虽然jps命令已经推出很久并且使用频率很高,但它仍然是一个“实验性质的,并且没有技术支持的”(Experimental and Unsupported)工具,日后可能会被转正,也有可能在某个JDK版本中无声无息地消失。
jps命令本质上是依靠Java程序读取tmp/hsperfdata_{user
}目录下的文件实现读取进程状态的功能。
jstat
jstat(JVM Statistics Monitoring Tool)是用于监控虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类加载、内存、垃圾收集、即时编译等运行时数据。
- 类加载:
-class
,监视类加载、卸载数量、总空间以及类装载所耗费的时间。 - 垃圾收集:
-gc
,-gccapacity
,-gccause
,-gcnew
,-gcnewcapacity
,-gcold
,-gcoldcapacity
,-gcmetacapacity
,-gcutil
,垃圾收集的相关信息。 - 运行期编译情况:
-printcompilation
,-compiler
。
jstat命令同样是依靠Java程序读取tmp/hsperfdata_{user
}目录下的文件实现的。
jstat命令作为一个纯命令行工具,只能在terminal中以纯文本的状态使用,在体验上不如JMC和VisualVM更直观和形象,但是在实际的生产环境中不一定可以使用图形界面,所以stat依然是一种常用的监控方式。
注意:此命令同样是实验性的且不受支持。
Jinfo
jinfo(Configguration Info for Java)是用于查看和调整虚拟机各项参数的工具,包括Java系统属性和JVM命令行标志(java -XX+)。你可能注意到,jps -v
命令也可以打印JVM命令行标志,但是jps
只能查看虚拟机启动时显式指定的参数列表。如果想知道没有被显式指定的参数列表,就需要使用jinfo了。
- Java System Properties
- VM Flags
- VM Arguments
比如,我们可以在不重启Java虚拟机的情况下,使用jinfo -flag MinHeapFreeRatio=30
修改空闲堆空间的最小百分比为30%。当然,也不是所有的参数都可以修改,我们可以通过java -XX:+PrintFlagsInitial
命令找到标记为manageable的配置参数。
注意:此命令同样是实验性的且不受支持。
Jmap
jmap(Memory Map for Java)是一个主要用于生成堆转储快照的工具。如果没有jamp命令,我们如何获取Java程序运行时的堆转储快照呢?我们可以在JVM启动的时候添加-XX:+HeapDumpOnOutOfMemoryError
参数使得虚拟机在内存溢出异常出现后自动生成堆转储快照文件,或者通过-XX:+HeapDumpOnCtrlBreak
使得使用[Ctrl][Break]按键触发堆转储过程。但是这样是很不自由的,jmap工具使得我们随时可以进行堆转储。
除此之外,jamp还可以:
- 查询 Java 堆的类加载器统计信息
- 查询finalize队列的执行情况
- 显示堆中对象的统计信息,包括类名,实例数量,占用空间大小
注意:此命令同样是实验性的且不受支持。
Jhat
jhat(JVM Heap Analysis Tool)工具是与jmap搭配使用的,用于解析jmap生成的堆转储快照。jhat 内置了一个 Web 服务器,解析结果后,可以在浏览器查看。 jhat 命令支持预先设计的查询,例如显示已知类 MyClass 的所有实例,或者对象查询语言 (OQL)。
但是,在实际场景中,jhat可能会有一点鸡肋,原因如下:
- 我们一般不会在服务器上直接分析dump文件,很可能不支持Web服务器或者性能开销较大。
- 既然已经在其他机器上分析了,为什么还要使用这个简陋的工具呢?我们自己使用专业的工具分析不行吗?
注意:此命令同样是实验性的且不受支持。
Jstack
jstack用于生成java虚拟机当前时刻线程快照的一个工具。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合。通过生成线程快照,主要是为了定位线程出现长时间停顿的原因,比如线程死锁,死循环等。
除此之外,如果Java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道Java程序是如何崩溃和在程序何处发生问题。
Jcmd
jcmd(JVM command)是一个虚拟机诊断命令工具。它可以将诊断命令请求发送到正在运行的Java虚拟机中。jcmd其实是一个多功能的工具箱,它整合了JDK自带的一些命令行工具的功能,比如jps,jmap,jinfo等都有替代的命令。按照命令大概可以分为下面几类:
- Compiler
- GC
- JFR
- JVMTI
- ManagementAgent
- Thread
- VM
可视化工具
JDK中除了一些基本的命令行工具,还提供了几个功能高度集成的可视化工具。这些功能通常易用性更强。
- Jconsole
- jhsdb
- VisualVM
- JMC
Jhsdb
Jhsdb是从JDK9开始引入的新的命令行工具。Jhsdb是一款基于服务性代理(Serviceability Agent ,SA )实现的进程外调试工具。它包括 clhsdb、debugd、hsdb、jstack、jmap、jinfo、jsnap 这些 mode 可以使用,其中有几个在名称和功能上与以前的 JDK 发行版中可用的各个命令行工具相对应。看得出来,官方想要 jhsdb 工具整合多个其他工具的功能,甚至还做了一些功能拓展。
Serviceability Agent (SA) 是一个 JDK 组件,用于提供快照调试、性能分析以及深入了解 Hotspot JVM 以及 Hotspot JVM 执行的 Java 应用程序。
- Class Broswer:查看所有 JVM 加载的 class,对应类内的方法等信息自然也都能查到。此外,还支持把一个 class dump 到本地。
- Code Viewer:对于一个类内的方法,有些时候需要分析方法的 JVM 指令或者 JIT 编译后的指令,可以使用这个工具,在输入 Class或者 Method的地址后,就会看到其对应的内容。
- 死锁检测(Deadlock Detection):检测Java代码层面的死锁,如果线程中存在死锁,则会显示线程死锁的信息和他们等待的锁;
- Find Value in Heap/Code Cache:通过指定对象的地址查看对象是否存在于Heap/Code Cache中
- 对象检视器(Interceptor):可以查看Java线程对象的基本信息,也可以查看虚拟机内部的C++结构体信息;
- 对象直方图(Object Histogram):可以查看当前堆内存中对象的直方图
服务性代理(SA)是HotSpot虚拟机中一组用于映射Java虚拟机运行信息的、主要基于Java语言(含少量JNI代码)实现的API集合。服务性代理根据HotSpot内部的数据结构作为参照物进行设计,把这些C++的数据抽象成Java模型对象,相当于HotSpot的C++代码的一个镜像。通过服务性代理的API,我们可以在一个独立的Java虚拟机进程里分析其他HotSpot虚拟机的内部数据,或者从HotSpot虚拟机进程内存中dump出的转储快照里面分析还原出它的运行状态细节。
TODO:SA的原理
JConsole
JConsole(Java Monitoring and Management Console)是一款基于JMX(Java Management Extensions)的可视化监控工具。它的原理是基于JMX的MBean(Managed Bean)技术对系统进行性能监控和修改。JMX是一种用于管理和监控Java应用程序的技术。它提供了一组API和工具,使开发人员能够在运行时监视和管理Java应用程序的各个方面,包括性能、资源使用、配置和调优等。MX架构基于一组标准MBean(Managed Bean),这些MBean是Java类的特殊对象,通过暴露其属性和操作来提供管理和监控功能。通过JMX代理,管理工具可以查询和修改MBean的属性值,执行MBean的操作,以及订阅和接收来自MBean的通知。
JConsole主要有以下几个功能:
- Overview
- Memory
- Threads
- Classes
- VM Summary
- MBeans
Java 提供了实现 MBean 的标准和规则,但平时我们几乎不需要开发 MBean。绝大多数的开发者接触到的也仅仅是使用 JDK 或者第三方定义好的 MBean。但是,我们如果想,也可以自己实现MBean,从而在JConsole中操作。
VisualVM
VisualVM是一款功能非常强大的性能监控和故障处理的程序。Oracle在VisualVM工具的官网上称其为“All-in-One Java Troubleshooting Tool”,足可见其能力之强大。
VisualVM使用了jvmstat,JMX,Serviceability Agent (SA) 和Attach API等多项技术为其服务。可以做到:
- 自动检测并列出本地和远程运行的 Java 应用程序,支持通过 JMX 连接手动定义应用程序。
- 展示虚拟机进程配置信息和环境信息:对于每个进程,VisualVM 显示基本的运行时信息:PID、主类、传递给 java 进程的参数、JVM 版本、JDK 主目录、JVM 标志和参数以及系统属性。
- 监控进程性能和内存:监视应用程序 CPU 使用情况、GC 活动、堆和元空间/永久代内存、加载的类和运行线程的数量。
- 方法级的程序运行性能分析,包括sampling和Instrumentation。
- 获取并分析线程转储(thread dump,堆转储(heap dump),Core dumps
- 离线程序快照:收集程序的运行时配置,线程dump,内存dump等信息建立一个快照,以便离线分析。
除此之外,因为VisualVM是一个基于NetBeans平台开发的工具,所以它还支持插件扩展,从而实现更多的功能。
JMC(JFR)
JFR是一套内建在HotSpot虚拟机内部的诊断和分析Java应用程序的工具。它集成在JVM中,几乎不会造成性能开销,官方声称在使用默认设置时,性能影响不到百分之一,因此即使在负载较重的生产环境中也可以使用。
JFR监控的开始和停止都不需要重启应用,监控过程对应用来说也是完全透明的,不需要对应用程序的源码做任何修改,也不需要基于特定的代理来运行。
JDK Mission Control 是一套先进的工具,可以对 Java Flight Recorder 收集的大量数据进行高效、详细的分析。
JFR的基本原理是基于事件(event)的。当某个事件发生时,这个事件的所有上下文数据将会以循环日志的形式被保存在内存或者某个指定的文件中。当采集完成,JMC从虚拟机的内存或者文件中读取并展示这些数据,完成分析和报告。
每个事件都有一个名称、一个时间戳和一个可选的负载。负载是与事件相关的数据,例如CPU使用率、事件前后的Java堆大小、锁持有者的线程ID等。大多数事件还包含有关事件发生的线程、事件发生时的堆栈跟踪以及事件持续时间的信息。
JFR会收集三种类型的事件:
- 持续时间事件:需要一些时间才能发生,并在完成时记录。我们可以设置持续时间事件的阈值,以便仅记录持续时间超过指定时间段的事件。这对于其他类型的事件是不可能的。
- 即时事件:立即发生,并立即记录。
- 定期记录样本事件(也称为可请求事件):以提供系统活动的样本。我们可以配置采样发生的频率。
默认情况下,JFR 在 JVM 中处于禁用状态。要启用 JFR,必须使用该选项启动 Java 应用程序-XX:+FlightRecorder
。由于 JFR 是一项商业功能,仅在基于 Java Platform, Standard Edition( Oracle Java SE Advanced和Oracle Java SE Suite )的商业包中提供,因此还必须使用选项启用商业功能-XX:+UnlockCommercialFeatures
。
https://www.cnblogs.com/flydean/p/jdk14-jfr-jmc-event-stream.html
第三方工具
总览
- Async-profiler
- Arthas
- JProfiler
- Parca
Async-profiler
Async-profiler是一个低开销的 Java 采样分析器,它不会遇到安全点偏差问题。它使用HotSpot 特定的 API 来收集堆栈信息,追踪内存分配。该分析器可与 OpenJDK、Oracle JDK ,以及其他基于 HotSpot JVM 的 Java 运行时配合使用。
Async-profiler 可以跟踪以下类型的事件:
- CPU周期
- 硬件和软件性能计数器,例如缓存未命中、分支未命中、页面错误、上下文切换等。
- Java 堆中的分配
- Contented lock尝试,包括 Java 对象监视器和 ReentrantLocks
Async-profiler主要有以下功能:
- CPU profiling
- ALLOCATION profiling
- Wall-clock profiling
- Java method profiling
我们常用的功能是 CPU 性能分析。在进行 CPU 性能分析时,仅需要非常低的性能开销就可以进行分析,这也是这个工具的优点之一。Async-profiler提供开箱即用的 Flame Graph 支持。指定 -o Flamegraph
参数将分析结果转储为交互式 HTML 火焰图。此外,如果目标文件名以 .html 结尾,则会自动选择火焰图输出格式。
Arthas
Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码以及不重启JVM的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。相比于其他工具,Arthas可以个性化地针对业务问题 进行分析。
Arthas是以终端命令的方式进行操作,它提供了一系列用于诊断的命令,包括dashboard,classloader,dump,heapdump,watch等等Arthas基于Instrumentation API 和Java Agent实现。
Instrumentation是Java提供的一个来自JVM的接口,该接口提供了一系列查看和操作Java类定义的方法,例如修改类的字节码、向classLoader的classpath下加入jar文件等。使得开发者可以通过Java语言来操作和监控JVM内部的一些状态,进而实现Java程序的监控分析,甚至实现一些特殊功能(如AOP、热部署)。
Java agent是一种特殊的Java程序(Jar文件),它是Instrumentation的客户端。与普通Java程序通过main方法启动不同,agent并不是一个可以单独启动的程序,而必须依附在一个Java应用程序(JVM)上,与它运行在同一个进程中,通过Instrumentation API与虚拟机交互。Java agent与Instrumentation密不可分,二者也需要在一起使用。因为Instrumentation的实例会作为参数注入到Java agent的启动方法中。
JProfiler
JProfiler是由 ej-technologies 公司开发的一款 Java 应用性能诊断工具。它也声称自己是All-in-One Java Profiler,主要聚焦于四个重要主题上。
- 方法调用 - 对方法调用的分析可以帮助您了解应用程序正在做什么,并找到提高其性能的方法。
- 内存分配 - 通过分析堆上对象、引用链和垃圾收集能帮您修复内存泄漏问题,优化内存使用。
- 线程和锁 - JProfiler 提供多种针对线程和锁的分析视图助您发现多线程问题。
- 高级子系统 - 许多性能问题都发生在更高的语义级别上。例如,对于JDBC调用,您可能希望找出执行最慢的 SQL 语句。JProfiler 支持对这些子系统进行集成分析。
JProfiler 包含用于采集目标 JVM 分析数据的 JProfiler agent、用于可视化分析数据的 JProfiler UI、提供各种功能的命令行工具,具体如下:
- JProfiler agent
JProfiler agent 是一个本地库,它可以在 JVM 启动时通过参数-agentpath:<path to native library>
进行加载或者在程序运行时通过 JVM Attach 机制进行加载。Agent 被成功加载后,会设置 JVMTI 环境,监听虚拟机产生的事件,如类加载、线程创建等。例如,当它监听到类加载事件后,会给这些类注入用于执行度量操作的字节码。
- JProfiler UI
JProfiler UI 是一个可独立部署的组件,它通过 socket 和 agent 建立连接。这意味着不论目标 JVM 运行在本地还是远端,JProfiler UI 和 agent 间的通信机制都是一样的。
JProfiler UI 的主要功能是展示通过 agent 采集上来的分析数据,此外还可以通过它控制 agent 的采集行为,将快照保存至磁盘,展示保存的快照。
- 命令行工具
JProfiler 提供了一系列命令行工具以实现不同的功能。
- jpcontroller - 用于控制 agent 的采集行为。它通过 agent 注册的 JProfiler MBean 向 agent 传递命令。
- jpenable - 用于将 agent 加载到一个正在运行的 JVM 上。
- jpdump - 用于获取正在运行的 JVM 的堆快照。
- jpexport & jpcompare - 用于从保存的快照中提取数据并创建 HTML 报告。