Using JFR both with ZGC degrades application throughput
Fabrice Bibonne
fabrice.bibonne at courriel.eco
Thu Jan 15 05:44:28 UTC 2026
Hi,
Yes turning off jdk.OldObjectSample event solved the issue : the real
time execution of my sample with zgc and JFR recording with
jdk.OldObjectSample turned off is now very close to that without JFR
recording.
Thank you very much.
Best regards.
Fabrice
Le 2026-01-14 19:30, Markus Gronlund a écrit :
> Hi again,
>
> I just remembered we have improved our ergonomics over the years.
>
> Therefore, there is a much easier way for you to do this without
> configuring anything in the .jfc files: you can simply override event
> settings on the command line. [1]
>
> -XX:StartFlightRecording:jdk.OldObjectSample#enabled=false
>
> Way easier!
>
> Cheers
>
> Markus
>
> [1] https://egahlin.github.io/2022/05/31/improved-ergonomics.html [2]
>
> Confidential- Oracle Internal
>
> From: hotspot-jfr-dev <hotspot-jfr-dev-retn at openjdk.org> On Behalf Of
> Markus Gronlund
> Sent: Wednesday, 14 January 2026 19:15
> To: Fabrice Bibonne <fabrice.bibonne at courriel.eco>
> Cc: hotspot-jfr-dev at openjdk.org
> Subject: RE: Using JFR both with ZGC degrades application throughput
>
> Hi Fabrice,
>
> Thank you very much for reporting this and also for providing a great
> reproducer.
>
> We have made some progress towards understanding the problem space, at
> least.
>
> To help you continue with your demonstrations, explanations, and
> comparisons, I only need you to do the following:
>
> In the jdk/lib/jfr directory, there are two files that control the
> default and profile sets of JFR events: default.jfc and profile.jfc,
> respectively.
>
> <event name="jdk.OldObjectSample">
>
> <setting name="enabled" control="old-objects-enabled">false</setting>
>
> <setting name="stackTrace"
> control="old-objects-stack-trace">false</setting>
>
> <setting name="cutoff" control="old-objects-cutoff">0 ns</setting>
>
> </event>
>
> Turn off the jdk.OldObjectSample event by setting enabled to false.
>
> This effectively turns off JFRs capability to monitor memory leaks in
> the background.
>
> With this small change, you should be back on track for proper
> comparisons, also when using JFR.
>
> Let me know if you have any questions. We will be thinking about how to
> solve this properly.
>
> Cheers for now
>
> Regards
>
> Markus
>
> Confidential- Oracle Internal
>
> From: hotspot-jfr-dev <hotspot-jfr-dev-retn at openjdk.org> On Behalf Of
> Fabrice Bibonne
> Sent: Monday, 12 January 2026 16:59
> To: hotspot-jfr-dev at openjdk.org
> Subject: Re: Using JFR both with ZGC degrades application throughput
>
> Here is a unique source code file for the reproducer (the big String is
> generated when starting as you suggested). It changes a little the
> results but the run with zgc + jfr is still taking lot of time.
>
> Thanks you for having a look.
>
> Fabrice
>
> Le 2026-01-12 10:56, Erik Gahlin a écrit :
>
>> Hi Fabrice,
>>
>> Thanks for reporting!
>>
>> Could you post the source code for the reproducer here? The 36 MB file
>> could probably be replaced with a String::repeat expression.
>>
>> JFR does use some memory, which could impact available heap and
>> performance, although the degradation you're seeing seems awfully
>> high.
>>
>> Thanks
>> Erik
>>
>> ________________________________________
>> From: hotspot-jfr-dev <hotspot-jfr-dev-retn at openjdk.org> on behalf of
>> Fabrice Bibonne <fabrice.bibonne at courriel.eco>
>> Sent: Sunday, January 11, 2026 7:23 PM
>> To: hotspot-jfr-dev at openjdk.org
>> Subject: Using JFR both with ZGC degrades application throughput
>>
>> Hi all,
>>
>> I would like to report a case where starting jfr for an application
>> running with zgc causes a significant throughput degradation (compared
>> to when JFR is not started).
>>
>> My context : I was writing a little web app to illustrate a case where
>> the use of ZGC gives a better throughput than with G1. I benchmarked
>> with grafana k6 my application running with G1 and my application
>> running with ZGC : the runs with ZGC gave better throughputs. I
>> wanted to go a bit further in explanation so I began again my
>> benchmarks with JFR to be able to illustrate GC gains in JMC. When I
>> ran my web app with ZGC+JFR, I noticed a significant throughput
>> degradation in my benchmark (which was not the case with G1+JFR).
>>
>> Although I did not measure an increase in overhead as such, I still
>> wanted to report this issue because the degradation in throughput with
>> JFR is such that it would not be usable as is on a production service.
>>
>> I wrote a little application (not a web one) to reproduce the problem
>> : the application calls a little conversion service 200 times with
>> random numbers in parallel (to be like a web app in charge and to
>> pressure GC). The conversion service (a method named
>> `convertNumberToWords`) convert the number in a String looking for the
>> String in a Map with the number as th key. In order to instantiate and
>> destroy many objects at each call, the map is built parsing a huge
>> String at each call. Application ends after 200 calls.
>>
>> Here are the step to reproduce :
>> 1. Clone https://framagit.org/FBibonne/poc-java/-/tree/jfr+zgc_impact
>> [1] (be aware to be on branch jfr+zgc_impact)
>> 2. Compile it (you must include numbers200k.zip in resources : it
>> contains a 36 Mo text files whose contents are used to create the huge
>> String variable)
>> 3. in the root of repository :
>> 3a. Run `time java -Xmx4g -XX:+UseZGC -XX:+UseCompressedOops
>> -classpath target/classes poc.java.perf.write.TestPerf #ZGC without
>> JFR`
>> 3b. Run `time java -Xmx4g -XX:+UseZGC -XX:+UseCompressedOops
>> -XX:StartFlightRecording -classpath target/classes
>> poc.java.perf.write.TestPerf #ZGC with JFR`
>> 4. The real time of the second run (with JFR) will be considerably
>> higher than that of the first
>>
>> I ran these tests on my laptop :
>> - Dell Inc. Latitude 5591
>> - openSUSE Tumbleweed 20260108
>> - Kernel : 6.18.3-1-default (64-bit)
>> - 12 × Intel(R) Core(tm) i7-8850H CPU @ 2.60GHz
>> - RAM 16 Gio
>> - openjdk version "25.0.1" 2025-10-21
>> - OpenJDK Runtime Environment (build 25.0.1+8-27)
>> - OpenJDK 64-Bit Server VM (build 25.0.1+8-27, mixed mode, sharing)
>> - many tabs opened in firefox !
>>
>> I also ran it in a container (eclipse-temurin:25) on my laptop and
>> with a windows laptop and came to the same conclusions : here are the
>> measurements from the container :
>>
>> | Run with | Real time (s) |
>> |-----------|---------------|
>> | ZGC alone | 7.473 |
>> | ZGC + jfr | 25.075 |
>> | G1 alone | 10.195 |
>> | G1 + jfr | 10.450 |
>>
>> After all these tests I tried to run the app with an other profiler
>> tool in order to understand where is the issue. I join the flamegraph
>> when running jfr+zgc : for the worker threads of the ForkJoinPool of
>> Stream, stack traces of a majority of samples have the same top lines
>> :
>> - PosixSemaphore::wait
>> - ZPageAllocator::alloc_page_stall
>> - ZPageAllocator::alloc_page_inner
>> - ZPageAllocator::alloc_page
>>
>> So many thread seem to spent their time waiting in the method
>> ZPageAllocator::alloc_page_stall when the JFR is on. The JFR periodic
>> tasks threads has also a few samples where it waits at
>> ZPageAllocator::alloc_page_stall. I hope this will help you to find
>> the issue.
>>
>> Thank you very much for reading this email until the end. I hope this
>> is the good place for such a feedback. Let me know if I must report my
>> problem elsewhere. Be free to ask me more questions if you need.
>>
>> Thank you all for this amazing tool !
Links:
------
[1] https://framagit.org/FBibonne/poc-java/-/tree/jfr+zgc_impact
[2] https://egahlin.github.io/2022/05/31/improved-ergonomics.html
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/hotspot-jfr-dev/attachments/20260115/2f95d08f/attachment-0001.htm>
More information about the hotspot-jfr-dev
mailing list