Is it possible to disable `-XX:+PrintCompilation` and `-verbose:gc"` at runtime?
Asked Answered
E

1

8

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?

Etzel answered 26/1, 2021 at 21:6 Comment(2)
Yes, it's possible. Which OS and JDK version are you interested in?Hb
@Hb I'm running on Linux and OSX, JDK 11.Etzel
H
9

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.

  1. 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
^^^^^^^^^^^^
  1. Find the offset of PrintCompilation symbol in libjvm.so:
$ nm /usr/java/jdk-11/lib/server/libjvm.so | grep PrintCompilation
000000000144d7ff b PrintCompilation
^^^^^^^^^^^^^^^^
  1. 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);
Hb answered 27/1, 2021 at 0:16 Comment(4)
Thanks! Is there an equivalent trick for OSX?Etzel
I wonder, when -XX:+PrintCompilation is not manageable directly, what is the reason for that? And couldn't it be unsafe to change it the way shown here?Bedlam
@Etzel Yes. Do you want to change the flag externally or from Java code?Hb
@Bedlam For historical reasons. I believe the flag can be manageable at runtime, just nobody cared before. It's safe to change the flag this way, as it is queried just a like regular bool variable, and there are no implicit dependencies on this flag other than for logging.Hb

© 2022 - 2024 — McMap. All rights reserved.