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?
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
? Unlikejinfo
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:
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
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
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?