Java Flight Recorder (JFR)
JFR allows you to collect low-level information relating to the Java virtual machine and the Java application. This information can then be used to understand the behavior of the Java application and identify any performance related issues (i.e., memory leaks). When configuring the JFR, one can control the amount of data to be recorded by:
Enabling and disabling event types.
Enabling and disabling stack traces.
Adjusting recording frequency.
JFR comes with several pre-configured profiles that can be used to collect different types of statistics about the JVM and Java application. One such profile is the default profile. It has been pointed out that the default profile can be always-on due to its very low performance overhead. Enabling certain types of events in JFR, however, can have a significant impact on the application’s performance.
In this blog, I will investigate the behavior of applications memory when we enable object (heap) statistics and class loading. These options can be enabled by creating a custom profile. Refer to this link for more information about custom templates and how to enable these options. When object statistics and class loading are enabled, JFR collects heap statistics (such as classes that take more than 0.5% of the heap and thread local allocation buffer statistics). Such information can be used for identifying memory leaks and so on.
Memory Impact Analysis
Let’s now have a look at the usage of memory before and after enabling object statistics. Note that JFRs provided in this blog are from WSO2 APIM GW node. The performance test is done for a period of 20 minutes. The two 10-minute sections (before and after) of these JFRS have been considered.
(Details of the performance test: APIM Version 2.0.0, set-up:distributed; scenario: number 2, concurrency: 150, number of nodes: 6, workload generator: JMETER.)
Before enabling object statistics:
After enabling object statistics:
Note that before enabling the object statistics, the memory usage curve closely follows a sawtooth pattern. After enabling objects statistics, there is some distortion in this pattern due to noise introduced by major garbage collections and the like. Notice that before enabling object statistics, the number of garbage collections was 181, out of which there was only one major garbage collection (refer to the figures below for the GC behavior). After enabling the heap statistics, there is a significant increase in the number of GC pauses. Note that there are 485 total GC pauses and that 104 of these GC pauses are due to the major garbage collections. After enabling the object statistics, the total GC time has increased significantly, i.e., from 5 seconds and 738 milliseconds to 1 minute 59 seconds 220 milliseconds.
It is important to note that after enabling the object statics, the GC pauses contributes to 20% of the total run time, whereas before enabling it, this value was about 1%.
GC pauses before enabling heap object statistics:
GC pauses after enabling object statistics:
In this article, I looked at the impact of enabling object statistics on the memory usage and the application's runtime. We noticed that object statistics events have a significant impact on the application’s performance. Once enabled, GC pauses contribute to 20% of the total runtime, whereas for the default profile, this value was about 1%.