Search code examples
javajvm-argumentsjinfo

Java option MaxDirectMemorySize reported differently by java vs. jinfo


I restarted a Java process with new memory options -Xms4G -Xmx4G -XX:MaxDirectMemorySize=6G and wanted to verify if these changes got correctly applied, especially the 6G of direct memory.

The first solution I found for verifying this was via java itself, but this simply reported a 0, implying that my new settings had no effect:

bash-4.4$ java -XX:+PrintFlagsFinal -version | grep MaxDirect
    uintx MaxDirectMemorySize                = 0                          {product}
openjdk version "1.8.0_242"
OpenJDK Runtime Environment (build 1.8.0_242-b08)
OpenJDK 64-Bit Server VM (build 25.242-b08, mixed mode)

A second solution I found later was via jinfo, which apparently confirm the 6G that I indended to set:

bash-4.4$ jinfo -flag MaxDirectMemorySize 1
-XX:MaxDirectMemorySize=6442450944

I've relied on the java -XX:+PrintFlagsFinal for other purposes before, but now I wonder why it doesn't return the expected values. Why are java and jinfo returning different results?


Solution

  • There's (at least) two different JVMs.

    [Expanding comment:] java {nothing} -XX:+PrintFlagsFinal -version creates a new JVM, changes none of its configuration from the default, and prints the resulting configuration, which is the default configuration with no changes -- and the default for MaxDirectMemSize is indeed zero.

    OTOH jinfo {option} pid attaches to an existing already running JVM and obtains or changes the configuration of that JVM (although the specific pid 1 isn't usually a JVM but it often is in a docker container as you are using). jps lists the running JVMs you can attach to, with options to include JVM arguments and/or application arguments.

    Does this imply that the same verification cannot be achieved with java? Unlike jinfo it cannot be attached to a running JVM?

    Yes and no; it gets a bit Wonderlandy.

    java by itself creates a new JVM, separate from any existing one. Normally this JVM runs a user-specified program, but with -version as you used it just prints version info and exits without running anything.

    Now, the attach API is accessible from (and actually written partly in) Java. What jinfo does in more detail is:

    1. create a new JVM; this doesn't use the java executable, so it isn't easily visible, but it actually is a JVM just like one from java

    2. use that JVM to run some predefined Java code, which used to be in JDK/lib/tools.jar; I haven't bothered to track down where it is (and exactly how to access it) in the new post-8 modulated Java

    3. that Java code when run in the jinfo JVM attaches to, and accesses information in, the specified other JVM, which was previously created and configured with java -Xvarious to run your application

    You can actually do steps 2 and 3 yourself; you could write Java code that uses the API to attach to a specified (or otherwise located) existing JVM and get the info you want, and use java to run in JVM#2 your code that accesses info in existing JVM#1. But why bother, when jinfo (and jstat jmap jconsole etc) already does what is needed?

    For that matter, jps also does this -- it runs its own JVM to run Java 'tool' code that uses the attach API to list JVMs. That's why the list produced by jps, unless filtered, includes jps itself. In fact, if you could run jps during the very short time jinfo is running, the jps list would include jinfo also -- and if you could determine the pid for jps and run jinfo on that pid during the very short time jps is running, you could get jinfo-type information on the jps JVM.

    Clear enough?