使用飞行记录器监控Java Applications
1.Java 监控工具Java 不仅仅是一种编程语言,而是一个非常丰富的生态系统,它有很多工具。JDK 包含的程序,允许我们编译自己的程序,以及监视其状态和 Java 虚拟机在程序执行的完整生命周期内的状态。JDK 提供的的 bin 文件夹包含可用于分析和监视的以下程序:Java VisualVM (jvisualvm.exe)JConsole (jconsole.exe)Java M...
1.Java 监控工具
Java 不仅仅是一种编程语言,而是一个非常丰富的生态系统,它有很多工具。JDK 包含的程序,允许我们编译自己的程序,以及监视其状态和 Java 虚拟机在程序执行的完整生命周期内的状态。
JDK 提供的的 bin 文件夹包含可用于分析和监视的以下程序:
- Java VisualVM (jvisualvm.exe)
- JConsole (jconsole.exe)
- Java Mission Control (jmc.exe)
- Diagnostic Command Tool (jcmd.exe)
我们建议浏览此文件夹的内容,了解我们掌握的工具。
在本教程中,我们将重点介绍 Java 飞行记录器。上述工具中不存在此,因为它不是独立程序。它的使用与上述两个工具密切相关 - Java 任务控制和诊断命令工具。
2.基本概念
Java 飞行记录器 (JFR) 是一种监视工具,用于在 Java 应用程序执行期间收集有关 Java 虚拟机 (JVM) 中事件的信息。JFR 是 JDK 分布的一部分,并集成到 JVM 中。
JFR 旨在尽可能少地影响正在运行的应用程序的性能。
为了使用 JFR,我们应该激活它。我们可以通过两种方式实现此目的:
启动Java应用程序时
在 Java 应用程序已运行时传递 jcmd 工具的诊断命令
JFR 没有独立工具。我们使用 Java 任务控制 (JMC),它包含一个插件,允许我们可视化 JFR 收集的数据。
这三个组件(JFR、jcmd 和 JMC)构成了一套完整的套件,用于收集正在运行的 Java 程序的低级运行时信息。在优化程序或诊断程序时,我们可能会发现此信息非常有用。
如果我们的计算机上安装了各种版本的 Java,请务必确保 Java 编译器 (javac)、Java 启动器 (java) 和上述工具(JFR、jcmd 和 JMC)来自同一 Java 版本。否则,由于不同版本的 JFR 数据格式可能不兼容,因此存在无法看到任何有用数据的风险。
JFR 有两个主要概念:事件和数据流。让我们简要地讨论一下。
- Events
JFR 收集运行 Java 应用程序时在 JVM 中发生的事件。这些事件与 JVM 本身的状态或程序的状态相关。事件具有名称、时间戳和其他信息(如线程信息、执行堆栈和堆的状态)。
JFR 收集三种类型的事件:
- 即时事件一旦发生,将立即记录
- 如果持续时间事件成功指定阈值,则记录持续时间事件
- 示例事件用于对系统活动进行采样
- Dataflow
JFR 收集的事件包含大量数据。因此,根据设计,JFR 的速度足够快,不会妨碍程序。
JFR 将有关事件的数据保存在单个输出文件 flight.jfr 中。
正如我们所知,磁盘 I/O 操作相当昂贵。因此,JFR 使用各种缓冲区来存储收集的数据,然后再将数据块刷新到磁盘。事情可能会变得稍微复杂一点,因为在同一时刻,一个程序可能有多个具有不同选项的注册进程。
因此,我们可能会在输出文件中找到比请求更多的数据,或者它可能不是按时间顺序排列的。如果我们使用 JMC,我们甚至可能没有注意到这一事实,因为它按时间顺序显示事件。
在某些极少数情况下,JFR 可能无法刷新数据(例如,当事件过多或断电时)。如果发生这种情况,JFR 会尝试通知我们输出文件可能缺少一段数据。
3.如何使用JFR
JFR 是一个实验功能,因此其使用可能会发生变化。事实上,在早期的发行中,我们必须激活商业功能,以便在生产中使用。但是,从 JDK 11 开始,我们可能会使用它而不激活任何内容。我们始终可以查阅官方的 Java 发行说明,以检查如何使用此工具。
对于 JDK 8,为了能够激活 JFR,我们应该使用选项 " +UnlockCommercialFeatures "和 " +FlightRecorder "启动 JVM。
如上所述,有两种方法可以激活 JFR。当我们在启动应用程序时同时激活它时,我们从命令行执行。当应用程序已在运行时,我们使用诊断命令工具。
3.1 命令行
首先,我们使用标准java编译器javac将程序的*.java文件编译成一个*.class。
编译成功后,我们可以使用以下选项启动程序:
java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder
-XX:StartFlightRecording=duration=200s,filename=flight.jfr path-to-class-file
其中到类文件的路径是应用程序的入口点 _.class 文件。
此命令启动应用程序并激活录制,录制将立即启动,持续不超过 200 秒。收集的数据保存在输出文件 flight.jfr 中。我们将在下一节中更详细地介绍其他选项。
3.2 诊断命令行
使用jcmd工具
jcmd 1234 JFR.start duration=100s filename=flight.jfr
在 JDK 11 之前,为了能够以这种方式激活 JFR,我们应该使用未锁定的商业功能启动应用程序:
java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -cp ./out/ com.baeldung.Main
应用程序运行后,我们使用其进程 ID 来执行各种命令,这些命令采用以下格式:
jcmd <pid|MainClass> <command> [parameters]
它的命令如下:
- JFR.start – starts a new JFR recording
- JFR.check – checks running JFR recording(s)
- JFR.stop – stops a specific JFR recording
- JFR.dump – copies contents of a JFR recording to file
每个命令都有一系列参数。例如,JFR.start 命令具有以下参数:
- name – name of the recording; it serves to be able to reference this recording later with other commands
- delay – dimensional parameter for a time delay of recording start, the default value is 0s
- duration – dimensional parameter for a time interval of the duration of the recording; the default value is 0s, which means unlimited
- filename – name of a file that contains the collected data
- maxage – dimensional parameter for the maximum age of collected data; the default value is 0s, which means unlimited
- maxsize – maximum size of buffers for collected data in bytes; the default value is 0, which means no max size
在本节的开头,我们已经看到了这些参数的使用示例。有关参数的完整列表,我们可能始终参阅 Java 飞行记录的官方文档。
尽管 JFR 设计为在 JVM 和应用程序的性能上尽可能少地占用空间,但最好通过设置至少一个参数来限制收集数据的最大量:持续时间、最大长度或最大大小。
5.例子
我们的程序把对象插入list直到出现OutOfMemeryError异常。
public static void main(String[] args) {
List<Object> items = new ArrayList<>(1);
try {
while (true){
items.add(new Object());
}
} catch (OutOfMemoryError e){
System.out.println(e.getMessage());
}
assert items.size() > 0;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
不用运行电脑,我们能发现一个缺点:这个while循环一直运行将导致CPU 飙高和内存占用。我们使用JFR来分析一下。
5.2 开始注册
用以下命令进行编译:
javac -d out -sourcepath src/main src/main/com/baeldung/flightrecorder/FlightRecorder.java
在 *out/com/baeldung/flightrecorder*
目录下会发现一个文件 *FlightRecorder.class*
java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder
-XX:StartFlightRecording=duration=200s,filename=flight.jfr
-cp ./out/ com.baeldung.flightrecorder.FlightRecorder
5.3 可视化
在视图的左侧,我们看到"常规"、内存、代码和线程等部分。每个部分包含包含详细信息的各种选项卡。例如,"代码"部分的选项卡"热方法"包含方法调用的统计信息:
在此选项卡中,我们可以发现示例程序的另一个缺点:方法 java.util.Array.grow(int)已调用 17 次,以便在每次没有足够的空间来添加对象时放大数组容量。
在更现实的程序中,我们可能会看到许多其他有用的信息:
有关已创建对象的统计信息,当它们被垃圾回收器创建和销毁时
关于线程的年表的详细报告,当他们被锁定或活动
应用程序正在执行的 I/O 操作。
更多推荐
所有评论(0)