IMLC.ME

Java Flight Recorder

Java Flight Record(JFR) 是 Oracle 发布的一款 JVM 监控工具。 JFR 不仅提供了远比其他工具详尽和全面的 JVM 数据,还没有太大的 overhead。 根据官方的说法,JFR 会有大概 2% 的性能损失。

使用 JRF 需要利用到 jcmd 命令行工具。

定时监控

jcmd 7060 JFR.start name=MyRecording settings=profile delay=20s duration=2m filename=/tmp/profiling.jfr

上方命令中,

  • 7060: JVM 进程 id。你可以用 jps 或者 ps 命令查看。不过其实直接输入 jcmd 然后回车,也会打印 JVM 进程列表
  • settings: JFR 的配置文件。默认有 default 和 profile。具体内容可以查看 JAVA_HOME 的 lib/jfr目录下的 jfc 文件。其内容是以 xml 格式定义的监控配置。
  • duration: JFR 监控时长。例子中,JFR 会在两分钟后自动停止,并生成记录文件到 filename 指定的位置。

不定时监控

JFR 也可以一直保持运行。不指定 duration 的情况下,

jcmd 7060 JFR.start name=MyRecording settings=profile # 开始监控
jcmd 7060 JFR.check # 查看运行状态
jcmd 7060 JFR.dump filename=/tmp/profiling.jfr # 导出记录文件,并不会终止监控
jcmd 7060 JFR.stop # 停止监控
jcmd 7060 JFR.stop filename=/tmp/profiling.jfr # 停止并导出记录文件

随 JVM 启动

随着 JFR 源代码迁移到 OpenJDK,开发者可以免费这项功能而无需付费。 自然地,-XX:+UnlockCommercialFeatures也变得没有必要了。

java \
-Xmx1024m \
-Xlog:gc*=debug:file=gc.log:utctime,uptime,tid,level:filecount=10,filesize=128m \
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.hprof \
-XX:StartFlightRecording=\
    disk=true, \
    dumponexit=true, \
    filename=recording.jfr, \
    maxsize=1024m,\
    maxage=1d,\
    settings=profile \
    path-to-gc-roots=true \
OOMEGenerator

记录文件分析

JDK Mission Control(JMC)

JDK Mission Control 是 Oracle 官方的 JFR 文件分析工具。 你可以到https://jdk.java.net/jmc/8/下载。

Preview

IntelliJ IDEA Ultimate

IntelliJ IDEA 的付费版提供了 JFR 支持。 你可以点击 IDEA 上方菜单的 Run -> Open Profiler Snapshot -> Open... 打开 jfr 文件。 (或者直接把 .jfr 文件拖进去)

Preview

jfr-flame-graph

不得不说,Oracle 确实不是一家注重产品界面设计的公司,JMC 的 flame view 做得有点丑。 IntelliJ IDEA 界面是好看,但是无法把火焰图保存成 SVG 格式。PNG 格式的图片不太方便查看栈太复杂的情况。

于是,有时候可能你需要用 https://github.com/chrishantha/jfr-flame-graph 生成一个 SVG 格式好看的火焰图。

可用参数

Syntax : JFR.start [options]

               Options:

                 delay           (Optional) Length of time to wait before starting to record
                                 (INTEGER followed by 's' for seconds 'm' for minutes or h' for
                                 hours, 0s)

                 disk            (Optional) Flag for also writing the data to disk while recording
                                 (BOOLEAN, true)

                 dumponexit      (Optional) Flag for writing the recording to disk when the Java
                                 Virtual Machine (JVM) shuts down. If set to 'true' and no value
                                 is given for filename, the recording is written to a file in the
                                 directory where the process was started. The file name is a
                                 system-generated name that contains the process ID, the recording
                                 ID and the current time stamp. (For example:
                                 id-1-2021_09_14_09_00.jfr) (BOOLEAN, false)

                 duration        (Optional) Length of time to record. Note that 0s means forever
                                 (INTEGER followed by 's' for seconds 'm' for minutes or 'h' for
                                 hours, 0s)

                 filename        (Optional) Name of the file to which the flight recording data is
                                 written when the recording is stopped. If no filename is given, a
                                 filename is generated from the PID and the current date and is
                                 placed in the directory where the process was started. The
                                 filename may also be a directory in which case, the filename is
                                 generated from the PID and the current date in the specified
                                 directory. (STRING, no default value)

                 maxage          (Optional) Maximum time to keep the recorded data on disk. This
                                 parameter is valid only when the disk parameter is set to true.
                                 Note 0s means forever. (INTEGER followed by 's' for seconds 'm'
                                 for minutes or 'h' for hours, 0s)

                 maxsize         (Optional) Maximum size of the data to keep on disk in bytes if
                                 one of the following suffixes is not used: 'm' or 'M' for
                                 megabytes OR 'g' or 'G' for gigabytes. This parameter is valid
                                 only when the disk parameter is set to 'true'. The value must not
                                 be less than the value for the maxchunksize parameter set with
                                 the JFR.configure command. (STRING, 0 (no max size))

                 name            (Optional) Name of the recording. If no name is provided, a name
                                 is generated. Make note of the generated name that is shown in
                                 the response to the command so that you can use it with other
                                 commands. (STRING, system-generated default name)

                 path-to-gc-root (Optional) Flag for saving the path to garbage collection (GC)
                                 roots at the end of a recording. The path information is useful
                                 for finding memory leaks but collecting it is time consuming.
                                 Turn on this flag only when you have an application that you
                                 suspect has a memory leak. If the settings parameter is set to
                                 'profile', then the information collected includes the stack
                                 trace from where the potential leaking object wasallocated.
                                 (BOOLEAN, false)

                 settings        (Optional) Name of the settings file that identifies which events
                                 to record. To specify more than one file, use the settings
                                 parameter repeatedly. Include the path if the file is not in
                                 JAVA-HOME/lib/jfr. The following profiles are included with the
                                 JDK in the JAVA-HOME/lib/jfr directory: 'default.jfc': collects a
                                 predefined set of information with low overhead, so it has minimal
                                 impact on performance and can be used with recordings that run
                                 continuously; 'profile.jfc': Provides more data than the
                                 'default.jfc' profile, but with more overhead and impact on
                                 performance. Use this configuration for short periods of time
                                 when more information is needed. Use none to start a recording
                                 without a predefined configuration file. (STRING,
                                 JAVA-HOME/lib/jfr/default.jfc)

               Event settings and .jfc options can also be specified using the following syntax:

                 jfc-option=value    (Optional) The option value to modify. To see available
                                     options for a .jfc file, use the 'jfr configure' command.

                 event-setting=value (Optional) The event setting value to modify. Use the form:
                                     <event-name>#<setting-name>=<value>
                                     To add a new event setting, prefix the event name with '+'.

               In case of a conflict between a parameter and a .jfc option, the parameter will
               take  precedence. The whitespace character can be omitted for timespan values,
               i.e. 20s. For more information about the settings syntax, see Javadoc of the
               jdk.jfr package.

               Options must be specified using the <key> or <key>=<value> syntax.

               Example usage:

                $ jcmd <pid> JFR.start
                $ jcmd <pid> JFR.start filename=dump.jfr
                $ jcmd <pid> JFR.start filename=%s
                $ jcmd <pid> JFR.start dumponexit=true
                $ jcmd <pid> JFR.start maxage=1h,maxsize=1000M
                $ jcmd <pid> JFR.start settings=profile
                $ jcmd <pid> JFR.start delay=5m,settings=my.jfc
                $ jcmd <pid> JFR.start gc=high method-profiling=high
                $ jcmd <pid> JFR.start jdk.JavaMonitorEnter#threshold=1ms
                $ jcmd <pid> JFR.start +HelloWorld#enabled=true +HelloWorld#stackTrace=true
                $ jcmd <pid> JFR.start settings=user.jfc com.example.UserDefined#enabled=true
                $ jcmd <pid> JFR.start settings=none +Hello#enabled=true

               Note, if the default event settings are modified, overhead may exceed 1%%.

References

Source Code - GitHub
JDK Mission Control User Guide