JFR 使用教程

JFR 飞行记录器是 JMC 中最重要的工具之一,它可以捕获Java应用程序在运行时的性能数据,包括线程活动、CPU使用情况、内存使用情况、网络流量等,然后将这些数据保存到文件中。然后开发人员可以使用 JMC 或者命令工具分析这个数据,帮助排查性能问题。

为了方便演示,编写一段测试代码,有下面几个方法。

  1. cpuHigh 方法,不断地做浮点运算,消耗 CPU 性能。
  2. allocate 方法,不断地分配 BigDecimal 对象,占用内存。
  3. readFile 方法,不断地读取文件内容,消耗 IO 资源。

一如既往,文章测试代码地址:https://github.com/niumoo/JavaNotes/blob/master/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java

下面介绍使用 JFR 可以分析几种常见问题。

JFR 启动记录

可以使用 JMC 直接设定捕获一段时间内的 JFR 记录。

JFR 记录

使用 JFR 记录了指定时长的数据后,会生成一个 .jfr 的数据文件,并自动打开 JMC 的 JFR 分析页面。如下图。

JFR 主页面

除此之外,还可以使用命令 jcmd 捕获一段时间的 JFR 记录。

➜  develop jps
32437 Jps
31510 HotCode
➜ jcmd 31510 JFR.dump name=1 filename=./recording.jfr
31510:
No recordings to dump from. Use JFR.start to start a recording.
➜ jcmd 31510 JFR.start delay=5s duration=20s settings=profile filename=/Users/darcy/recording.jfr
31510:
Recording 3 scheduled to start in 5 s. The result will be written to:

/Users/darcy/recording.jfr
➜ jcmd 31510 JFR.check
31510:
Recording 3: name=3 duration=20s (running)
➜ jcmd 31510 JFR.check
31510:
No available recordings.

Use jcmd 31510 JFR.start to start a recording.
➜  develop ll ~/ | grep jfr
-rw-r--r--    1 darcy  staff   2.0M  3 14 20:22 recording.jfr

上面的示例中,要进行 JFR 转存的进程为 31510,记录时长 20s,并保存到 /Users/darcy/recording.jfr 文件中。

JFR 分析内存

在 JFR 的内存页面,可以看到类的内存占用情况,因为测试代码中在不断地分配 BigDecimal 对象到 List ,这里也可以看到 java.match.BigDecimal 对象占用了较多内存。

并且在下方的 Flame View 视图中还能看分配调用堆栈,可以看到是 allocate 方法分配过来的。

JFR 内存

在内存的活动对象页面,可以进一步查看活动对象的内存占用来源,如果继续看 BigDecimal 对象的话,可以看到它的堆栈信息,以及所在线程名称为 memory_allocate_thread

JFR 内存活动对象

JFR 分析CPU

在方法概要分析中,可以简单看到某些操作使用了产生了多少事件,事件产生较多的线程可以从侧面说明它也占用了较多的 CPU 资源。

JFR 方法概要分析

这个图中可以看到 cpuHigh 方法产生了最多的事件,所在的线程为 cpu_high_thread,从 Flame View 中还可以看到调用的堆栈信息。

JFR 分析网络

通过套接字I/O 页面可以看到网络传输情况,因为在测试代码中不涉及网络传输,所以这里捕获到的只有 JMC 和 JFR 与进程通信的 RMI 协议信息。

JFR 套接字

JFR 分析 IO

通过 文件 I/O 页面可以查看进程的 I/O 操作情况,在示例代码中,启动了 readFile 方法不断地读取文件内容,从下面的截图中可以看到在不断地读取 info.txt 文件,现成名称为 read_file_method

JFR IO