JDK 21 comes with a new JFR view command that displays aggregated event data in the shell. The command can be used to view information about an application without the need to dump a recording file, or open up JDK Mission Control.
$ jcmd 1739 JFR.view hot-methods
Java methods that execute the most
Method Samples Percent
------------------------------------------------------------- ------- -------
sun.java2d.marlin.Renderer._endRendering(...) 1659 42.99%
sun.java2d.marlin.MarlinTileGenerator.getAlphaRLE(...) 592 15.34%
sun.java2d.marlin.MarlinCache.copyAARowRLE_WithBlockFlags(...) 447 11.58%
sun.java2d.marlin.MarlinCache.copyAARowNoRLE(...) 246 6.37%
sun.java2d.marlin.Renderer.addLine(...) 89 2.31%
sun.java2d.marlin.Renderer.copyAARow(...) 86 2.23%
sun.java2d.marlin.ArrayCacheInt.fill(...) 73 1.89%
...
To use the command, first start a recording:
$ java -XX:StartFlightRecording -jar my.jar
Once the application is running, the jcmd tool can be used to list all running Java processes:
$ jcmd
37417 my.jar
37418 jdk.jcmd/sun.tools.jcmd.JCmd
Use the PID or the name of the jar/class file together with JFR.view and the name of the view to display, for example:
$ jcmd 37417 JFR.view allocation-by-site
Allocation by Site
Method Allocation Pressure
------------------------------------------------------- -------------------
java.lang.StringUTF16.compress(char[], int, int) 37.50%
java.lang.Integer.valueOf(int) 13.75%
spec.jbb.infra.Util.TransactionLogBuffer.getLine(...) 9.22%
java.math.BigDecimal.valueOf(long, int) 8.92%
spec.jbb.CustomerReportTransaction.process(...) 7.55%
java.math.BigDecimal.layoutChars(boolean) 5.71%
...
The allocation-by-site view is built from the jdk.ObjectAllocationSample event that was added in JDK 16. To see a list of all available views, just omit the view name. JDK 21 comes with 70 predefined views, with more to be added in future releases. The views are grouped into three categories: Java Virtual Machine, Environment, and Application.
$ jcmd 37417 JFR.view
...
Java virtual machine views:
class-modifications gc-concurrent-phases longest-compilations
compiler-configuration gc-configuration native-memory-committed
compiler-phases gc-cpu-time native-memory-reserved
compiler-statistics gc-pause-phases safepoints
deoptimizations-by-reason gc-pauses tlabs
deoptimizations-by-site gc-references vm-operations
gc heap-configuration
Environment views:
active-recordings cpu-information jvm-flags
active-settings cpu-load native-libraries
container-configuration cpu-load-samples network-utilization
container-cpu-throttling cpu-tsc recording
container-cpu-usage environment-variables system-information
container-io-usage events-by-count system-processes
container-memory-usage events-by-name system-properties
Application views:
allocation-by-class exception-count native-methods
allocation-by-site file-reads-by-path object-statistics
allocation-by-thread file-writes-by-path pinned-threads
class-loaders finalizers socket-reads-by-host
contention-by-address hot-methods socket-writes-by-host
contention-by-class latencies-by-type thread-allocation
longest-class-loading thread-count
contention-by-thread memory-leaks-by-class thread-cpu-load
exception-by-message memory-leaks-by-site thread-start
exception-by-site modules
By default, a view will cover the last 32 MB of data, although not further back than 10 minutes. To set a custom time range, use the parameters maxage and maxsize. They work similarly to the maxage and maxsize parameters for the JFR.dump command.
$ jcmd my.jar JFR.view maxage=1h maxsize=2000MB gc-pauses
GC Pauses
---------
Total Pause Time: 2.93 s
Number of Pauses: 272
Minimum Pause Time: 0.471 ms
Median Pause Time: 7.82 ms
Average Pause Time: 10.8 ms
P90 Pause Time: 10.2 ms
P95 Pause Time: 20.9 ms
P99 Pause Time: 256 ms
P99.9% Pause Time: 256 ms
Maximum Pause Time: 256 ms
The format of the output can be controlled using the parameters width, cell-height and truncate. The width parameter sets the maximum number of characters to use, for example 120. If not set, the table will be sized automatically.
The cell-height parameter determines the number of lines to use inside a table cell. For most views, it’s 1 by default, but can be set to a higher value in case the text doesn’t fit. This option is especially useful for displaying multi-line stack traces.
Finally, the truncate parameter can be set to beginning or end to decide if the first or last characters should be omitted in case the text overflows. By default, truncation happens at the end.
$ jcmd my.jar JFR.view cell-height=3 truncate=beginning width=80 system-processes
System Processes
First Observed Last Observed PID Command Line
-------------- ------------- ----- --------------------------------------------
13:22:57 13:24:29 13028 C:\Program Files (x86)\Intel\Intel(R) Rapid
Storage Technology enterprise\IAStorIcon.exe
13:22:57 13:24:29 16200 C:\Program Files\Git\git-bash.exe
13:22:57 13:24:29 7232 C:\Program Files\Microsoft Visual Studio\202
2\Enterprise\Common7\IDE\PerfWatson2.exe
13:22:57 13:24:29 18216 C:\Program Files\Microsoft Visual Studio\202
2\Enterprise\Common7\IDE\VC\vcpackages\x86\V
CPkgSrv.exe
13:22:57 13:24:29 8536 C:\Program Files\Microsoft Visual Studio\202
2\Enterprise\Common7\IDE\devenv.exe
13:22:57 13:24:29 15228 C:\Program Files\Microsoft Visual Studio\202
2\Enterprise\Common7\ServiceHub\Hosts\Servic
eHub.Host.CLR.AnyCPU\ServiceHub.Host.CLR.exe
13:22:57 13:24:29 14128 ...es\Microsoft Visual Studio\2022\Enterpris
e\Common7\ServiceHub\Hosts\ServiceHub.Host.C
LR.AnyCPU\ServiceHub.TestWindowStoreHost.exe
The view command can also be used against a recording file by using the bin/jfr tool. A file can be created by setting the filename parameter with the -XX:StartFlightRecording option. When the JVM exits, the recording contents are written to the file.
Instead of a view, the name of a JFR event can be specified. In the following example, a custom event is created using the jdk.jfr event API. In the rendered output, the column headers get their name from the Label annotation and the bytes formatting comes from the DataAmount annotation.
import jdk.jfr.*;
public class Example {
@Name("example.FreeMemory")
@Label("Free Memory")
static class FreeMemoryEvent extends Event {
@Description("An approximation of the amount of memory available for allocation")
@Label("Free Memory")
@DataAmount(DataAmount.BYTES)
long free;
}
public static void main(String... args) throws Exception {
for(int i = 0; i < 3; i++) {
checkFreeMemory();
Thread.sleep(1000);
}
}
public static void checkFreeMemory() {
FreeMemoryEvent event = new FreeMemoryEvent();
event.begin();
event.free = Runtime.getRuntime().freeMemory();
event.commit();
}
}
To run the program and display the events:
$ java -XX:StartFlightRecording:filename=recording.jfr Example.java
$ jfr view --cell-height 2 FreeMemory recording.jfr
Free Memory
Start Time Duration Event Thread Stack Trace Free Memory
---------- --------- ---------------- ----------------------------- -----------
12:25:29 0.0213 ms main Example.checkFreeMemory() 240.7 MB
Example.main(String[])
12:25:30 0.0114 ms main Example.checkFreeMemory() 238.0 MB
Example.main(String[])
12:25:31 0.0218 ms main Example.checkFreeMemory() 237.7 MB
Example.main(String[])
To inspect what events are contained in a recording, use the summary command:
$ jfr summary recording.jfr
The parser that reads the file only parses the events that make up the view, which makes the process quick in most cases. Internally, the views are built using a query language. To see the query that makes up a view, specify the –verbose parameter.
$ jfr view --verbose gc recording.jfr
Garbage Collections
Start GC ID Type Heap Before GC Heap After GC Longest Pause
(startTime) (gcId) (eventType.label) (heapUsed) (heapUsed) (longestPause)
----------- ------ ------------------------ -------------- ------------- --------------
13:16:44 0 Young Garbage Collection 409.7 MB 3.1 MB 10.0 ms
13:16:44 1 Old Garbage Collection 3.1 MB 2.6 MB 21.8 ms
13:16:45 2 Young Garbage Collection 330.4 MB 3.9 MB 1.40 ms
13:16:45 3 Old Garbage Collection 3.9 MB 3.5 MB 32.1 ms
13:16:45 4 Young Garbage Collection 3.5 MB 3.5 MB 0.471 ms
13:16:45 5 Old Garbage Collection 3.5 MB 3.5 MB 20.0 ms
13:16:58 6 Young Garbage Collection 2.0 GB 33.0 MB 29.4 ms
...
COLUMN 'Start', 'GC ID', 'Type', 'Heap Before GC', 'Heap After GC', 'Longest Pause'
FORMAT none, none, missing:Unknown, none, none, none SELECT G.startTime, gcId,
[Y|O].eventType.label, B.heapUsed, A.heapUsed, longestPause FROM GarbageCollection AS G,
GCHeapSummary AS B, GCHeapSummary AS A, OldGarbageCollection AS O,
YoungGarbageCollection AS Y WHERE B.when = 'Before GC' AND A.when = 'After GC' GROUP BY
gcId ORDER BY G.startTime
In the above example, the view consists of events from four different event types, jdk.GarbageCollection, jdk.GCHeapSummary, jdk.YoungGarbageCollection and jdk.OldGarbageCollection. The events are tied together using the gcId in the GROUP BY clause. The query language, currently experimental, is designed to simplify the process for OpenJDK engineers to define views. In the future, it may be exposed for end-users as well.
To try out the new view command, download builds of JDK 21
Command-Line Reference
jfr view [--verbose]
[--width <integer>]
[--truncate <mode>]
[--cell-height <integer>]
<view>
<file>
--verbose Displays the query that makes up the view
--width <integer> The width of the view in characters. Default value depends on the view
--truncate <mode> How to truncate content that exceeds space in a table cell.
Mode can be 'beginning' or 'end'. Default value is 'end'
--cell-height <integer> Maximum number of rows in a table cell. Default value depends on the view
<view> Name of the view or event type to display. See list below for
available views
<file> Location of the recording file (.jfr)
jcmd <pid> JFR.view [options]
Options:
cell-height (Optional) Maximum number of rows in a table cell. (INTEGER, no default value)
maxage (Optional) Length of time for the view to span. (INTEGER followed by
's' for seconds 'm' for minutes, or 'h' for hours; default value is 10m)
maxsize (Optional) Maximum size for the view to span in bytes if one of
the following suffixes is not used: 'm' or 'M' for megabytes OR
'g' or 'G' for gigabytes. (STRING, default value is 32MB)
truncate (Optional) How to truncate content that exceeds space in a table cell.
Mode can be 'beginning' or 'end'. (STRING, default value 'end')
verbose (Optional) Displays the query that makes up the view.
(BOOLEAN, default value false)
<view> (Mandatory) Name of the view or event type to display.
See list below for available views. (STRING, no default value)
width (Optional) The width of the view in characters.
(INTEGER, no default value)