Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 316
merlin2011 Avatar asked Jan 26 '21 21:01

merlin2011


1 Answers

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);
like image 100
apangin Avatar answered Nov 16 '22 01:11

apangin