As suggested in this answer, I am using the following flags when running performance tests.
-XX:+PrintCompilation
-verbose:gc
This was very useful for debugging what JVM activities were happening during the timing phase, but the output is less useful when I am merely computing statistics and printing output about the benchmark that just ran.
Is there a way to disable one or both of these flags at runtime so that I can turn them off after the timing phase?
It's easy to turn off GC logs in runtime, since GC logs are included in Unified JVM Logging framework.
From the command line
jcmd <pid> VM.log what=gc=off
From within the application
ManagementFactory.getPlatformMBeanServer().invoke(
new ObjectName("com.sun.management:type=DiagnosticCommand"),
"vmLog",
new Object[]{new String[]{"what=gc=off"}},
new String[]{"[Ljava.lang.String;"}
);
Unfortunately, -XX:+PrintCompilation
is not a manageable flag and does not obey Unified JVM Logging. However, it's possible to change it, too.
I already showed in this answer how to modify a JVM flag externally using the Serviceability Agent. Here is one more way to do this.
The idea is to find the memory address of the flag and modify the value right in the memory. Below is an example how to achieve this on Linux.
$ grep libjvm.so /proc/<pid>/maps
7f57435ca000-7f574470d000 r-xp 00000000 fd:00 2342674 /usr/java/jdk-11/lib/server/libjvm.so
^^^^^^^^^^^^
PrintCompilation
symbol in libjvm.so
:$ nm /usr/java/jdk-11/lib/server/libjvm.so | grep PrintCompilation
000000000144d7ff b PrintCompilation
^^^^^^^^^^^^^^^^
0
into the process memory at the address base + offset
:$ printf '\x00' | dd of=/proc/<pid>/mem bs=1 count=1 seek=$((0x7f57435ca000 + 0x144d7ff)) conv=notrunc
That's it. PrintCompilation
flag has been turned off.
Bonus
The same trick can be done directly from a Java application: read /proc/pid/maps
like a regular file, parse ELF format of libjvm.so
to find the symbol offset, and finally use Unsafe
to write a byte at the given address. Here is the complete example.
Update
I've added a macOS example of modifying JVM flags in runtime from within a Java application. The usage is as simple as
VMFlags.setBooleanFlag("PrintCompilation", true);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With