Why is a Jira Data Center node consuming more memory than its configured -Xmx value?
Platform Notice: Data Center - This article applies to Atlassian products on the Data Center platform.
Note that this knowledge base article was created for the Data Center version of the product. Data Center knowledge base articles for non-Data Center-specific features may also work for Server versions of the product, however they have not been tested. Support for Server* products ended on February 15th 2024. If you are running a Server product, you can visit the Atlassian Server end of support announcement to review your migration options.
*Except Fisheye and Crucible
Summary
Users are seeing the Jira node is consuming more memory as operating system process than configured Xmx value.
Environment
Any version of Jira (both Software and Service Management) running on Java 8 or higher.
Cause
Calculating JVM memory consumption
The maximum heap value for the application's JVM has been correctly configured; however, it has been discovered that the JVM is utilizing even more memory than specified.
It should be noted that the value of the -Xmx parameter specifies only the maximum size of the Java heap and does not account for all other memory consumed by the JVM.
This includes the Permanent Generation (known as Metaspace from JDK 8 onward), the CodeCache, the native C++ heap utilized by other JVM internals, space allocated for thread stacks, direct byte buffers, garbage collection overhead, and various other factors. All of these contribute to the overall memory consumption of the JVM."
You can calculate the memory used by a JVM process as follows
JVM memory = Heap memory+ Metaspace + CodeCache + (ThreadStackSize * Number of Threads) + DirectByteBuffers + Jvm-native
Therefore, JVM memory usage can be more than the -Xmx value under peak business load.
Components of JVM memory consumption
- Metaspace: In the versions of JDK prior to 8, the storage area for classes and methods used in the application was known as Permanent Generation, or "perm." This area was contiguous with the Java heap. storage area for classes and methods used in the application was previously known as Permanent Generation or perm in the prior version of JDK 8, and it was contiguous with the Java heap. However, from JDK 8 onward, Permanent Generation has been replaced by Metaspace which is not contiguous with the Java heap.
However, starting with JDK 8, the Permanent Generation has been replaced by Metaspace, which is no longer contiguous with the Java heap. Metaspace is allocated in native memory, and its usage can be limited with the `MaxMetaspaceSize` parameter. By default, Metaspace does not have a limit, but it starts with a very low default size and is designed to grow gradually as needed. This growth is because Metaspace only contains class metadata, while all live Java objects are allocated in the heap memory.
Consequently, the size of Metaspace is typically much lower than that of the Permanent Generation. It's generally unnecessary to specify the maximum size for Metaspace unless you encounter a large memory leak problem. - CodeCache: The JVM produces native code for various purposes, such as the interpreter loop that is generated dynamically, JNI stubs and Java methods compiled into native code by JIT compiler. The CodeCache area is mainly affected by the JIT compiler.
- ThreadStackSize: The thread stack size in bytes can be set by using the -XX:ThreadStackSize=<size> option or the -Xss=<size> option. To indicate kilobytes, append k or K; to indicate megabytes, append m or M; and to indicate gigabytes, append g or G. The default value for -XX:ThreadStackSize depends on the underlying operating system and architecture.
$ jinfo -flag ThreadStackSize JAVA_PID