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.
- Find the base address of the loaded JVM library:
$ grep libjvm.so /proc/<pid>/maps
7f57435ca000-7f574470d000 r-xp 00000000 fd:00 2342674 /usr/java/jdk-11/lib/server/libjvm.so
^^^^^^^^^^^^
- Find the offset of
PrintCompilation
symbol in libjvm.so
:
$ nm /usr/java/jdk-11/lib/server/libjvm.so | grep PrintCompilation
000000000144d7ff b PrintCompilation
^^^^^^^^^^^^^^^^
- Now write
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);