CodeX
Published in

CodeX

Let’s talk about Java/JVM flags

Why would you want to know this? Well, in order to be able to tune an application and identify performance issues it’s important to understand what flags are actually being used by your application and possibly why.

TL;DR
You can view the flags used in your java application in multiple ways. Either by specifying a flag on the command line (-XX:+PrintFlagsFinal) or by using jcmd or jinfo on an active VM.

I’m running OpenJDK 13, in case you get different results please consult your specific JVM implementations documentation. Most of what is written here applies to other java versions as well.

Process ID

Most commands to monitor an active JVM requires that you identify the process id (PID) of the application. A simple way to retrieve the PID is using JPS [1] but you can also retrieve it from code if needed. Here I have started a simple program that loops forever called JavaFlags.

> jps
...
1966 JavaFlags
...

If you want to retrieve it by code take a loop at the example below which illustrates how to get the PID of the current process and other processes started with the java command.

Which provides the following output.

current process PID: 2016
PID name
---------- ----------
2016 PidFromCode
...
1966 JavaFlags

Now that we got the PID we are able to use other java tools to get more information about the running JVM. This article will talk about how to figure out what arguments was provided to the JVM and from where. Future articles will talk about how to actually monitor and investigate possible issues and tune the application.

View flags

There are in fact multiple ways you can retrieve the flags of an active JVM.

Side note
It is possible to tell the JVM to print the flags it uses on startup using a jvm flag but here we assume that this flag was not provided. I have included it below for those who are interested.

> java -XX:+PrintFlagsFinal ...

To get information about this JVM and its flags you can run the following command.

> java -XX:+PrintFlagsFinal -version

Show all

The following command prints the same information as the aforementioned flag using jcmd of an active VM [2].

> jcmd {PID} VM.flags -all
2636:
[Global flags]
...
bool BranchOnRegister = false {C2 product} {default}
bool C1OptimizeVirtualCallProfiling = true {C1 product} {default}
...
uintx InitialCodeCacheSize = 2555904 {pd product} {default}
size_t InitialHeapSize = 402653184 {product} {ergonomic}
...
uintx MaxHeapFreeRatio = 70 {manageable} {default}
size_t MaxHeapSize = 10737418240 {product} {command line}
...
size_t SoftMaxHeapSize = 6442450944 {manageable} {ergonomic}

The first brackets can contain lots of different values, below are some of the most common.

  • product: The default value of this flag is the same across all platforms, in other words, it’s a product build default value.
  • pd product: The default value of this flag is platform dependent (e.g. linux-x64)
  • manageable: The value of this flag can be set during runtime. For instance using jinfo as explained below [3].
  • C1|C2 product: The default value of this flag is specific to C1 (client) and C2 (server) JIT compiler. The difference between these compilers is out of scope of this article. Shortly, client compiler runs faster but produces less optimized code than C2. Which one is used depends on your platform but can be overridden in some instances, on most machines today both are used due to tiered compilation being the default since java 8.
  • C1|C2 diagnostic: The flag provides diagnostic info and is not used for tuning.
  • ARCH product: The flag only exists for some architectures and constant for others.
  • lp64_product: The flag only exists for 64-bit JVM and is constant for 32-bit versions.
  • commercial: The flag is only available for commercial version.
  • experimental: The flag is available if experimental mode is specified using -XX:+UnlockExperimentalVMOptions

The second brackets can be one of the following. Note that in previous versions, this bracket was not there and instead it was specified if the flag had a non-default value with a colon before the equal sign (“:=”).

  • {default}: The value for this flag is a default value for this JVM version.
  • {ergonomic}: The value was set to an optimal value according to the JVM taking into account the specific machine it is running on (e.g. OS, 32/64-bit or number of CPU:s).
  • {command line}: The flag was set on the command line which always takes precedence (if a flag is specified multiple times, the last occurrence is used).
  • {attach}: The flag was changed during runtime, only applicable for manageable flags.

Show specific flag

You can also view the current value of a flag using jinfo like this.

> jinfo -flag SoftMaxHeapSize {PID}
-XX:SoftMaxHeapSize=2000
> jinfo -flag HeapDumpBeforeFullGC {PID}
-XX:+HeapDumpBeforeFullGC

Setting flags

The most common way of setting flags is on the command line. The syntax differs depending on if it’s a boolean or a value flag.

Boolean examples

> java -XX:+BranchOnRegister (enables)> java -XX:-BranchOnRegister (disables)

Value examples

> java -XX:SoftMaxHeapSize=2G (2GB)> java -XX:SoftMaxHeapSize=2M (2MB)> java -XX:SoftMaxHeapSize=2K (2KB)

Setting a flag during runtime

You can also set some flags (if they are specified as manageable) during runtime. First get the PID as explained above then you can run the following command. If you try and set a non-manageable flag you will get an error (on earlier versions I believe this was silently ignored).

Boolean examples

> jinfo -flag +HeapDumpBeforeFullGC {PID} (enables)> jinfo -flag -HeapDumpBeforeFullGC {PID} (disables)

Value examples
Note here that you cannot use a unit such as K, M, or G but you have to specify the exact value.

> jinfo -flag SoftMaxHeapSize=2048 {PID} (sets it to 2M)

Finally, some flags have aliases and can be specified by either or. For instance setting the maximum heap size.

> java -Xmx3G -XX:+PrintFlagsFinal -version | grep MaxHeapSize
size_t MaxHeapSize = 3221225472 {product} {command line}
...
> java -XX:MaxHeapSize=3G -XX:+PrintFlagsFinal -version | grep MaxHeapSize
size_t MaxHeapSize = 3221225472 {product} {command line}
...

The only issue with this is that jinfo will not recognize one of the alises, for the case above using Xmx you will get an not found error.

> jinfo -flag Xmx {PID}
no such flag 'Xmx'

More information about this and other flags can be found here and here [4, 5].

References

[1] Java Virtual Machine Process Status Tool (JPS)
https://docs.oracle.com/javase/7/docs/technotes/tools/share/jps.html

[2] The jcmd Command
https://docs.oracle.com/en/java/javase/13/docs/specs/man/jcmd.html

[3] jinfo add reference here

[4] The java Command
https://docs.oracle.com/en/java/javase/13/docs/specs/man/java.html

[5] Java HotSpot VM Options
https://www.oracle.com/java/technologies/javase/vmoptions-jsp.html

--

--

Everything connected with Tech & Code. Follow to join our 1M+ monthly readers

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store