How to use Java Native Memory Tracking (NMT) to obtain JVM memory usage details

Still need help?

The Atlassian Community is here for you.

Ask the community


Platform notice: Server and Data Center only. This article only applies to Atlassian products on the Server and Data Center platforms.

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

Purpose

Atlassian applications generally consume more physical server memory than what is configured using the -Xmx or -XX:MaxHeapSize JVM parameters. This is expected and intended behavior due to how the JVM allocates memory, as there are more memory categories that Java uses beyond just Heap. However, it is not easy nor enabled by default to identify these other memory categories in order to account for all memory used by the Java process, and as such, administrators are often left wondering where the rest of the consumed memory is.

The purpose of this article is not to explain how to tune or otherwise optimize JVM memory usage; rather, this article serves to help administrators account for unexpected memory overhead beyond the Heap memory that they have configured for their application. Troubleshooting and tuning Java memory usage based on the results of NMT is out of scope of Atlassian Support, and the support team may not be able to assist with questions and concerns that arise based on these results.

Solution

To address this, it is possible to use Java's Native Memory Tracking functionality in order to track a JVM's internal memory usage. This will break down a JVM's memory consumption by category, which helps explain how other memory categories beyond Heap contribute to a JVM's memory consumption. This feature is not enabled by default, and enabling it involves a restart of the JVM. Further details and examples of this functionality in action can also be found in Oracle's documentation here: Native Memory Tracking - Usage and Examples

Per Native Memory Tracking - Usage and Examples, enabling NMT can cause a performance drop, and memory usage will be increased due to monitoring/tracking overhead.

Enabling NMT will result in a 5-10 percent JVM performance drop and memory usage for NMT adds 2 machine words to all malloc memory as malloc header. NMT memory usage is also tracked by NMT.

We do not recommend enabling NMT for extended periods of time in Production environments, as a result. We'd suggest only enabling it as needed in order to obtain the necessary information before removing it.


(lightbulb) To enable the NMT feature:

  1. Shut down the application
  2. Add the following argument to the application's JVM parameters:
    1. -XX:NativeMemoryTracking=summary
  3. Start the application

(lightbulb) To obtain the NMT details once the feature is enabled:

  1. Perform the following command as the OS user who is running the application, being sure to replace '<pid>' with the PID of the application being analyzed
    1. jcmd <pid> VM.native_memory summary
  2. The categories and their descriptions are defined here: NMT Memory Categories


Example Output

Click here to expand...


kevin@kevin-VirtualBox:~/atlassian/jira/bin$ jcmd 2776 VM.native_memory summary
2776:

Native Memory Tracking:

Total: reserved=3553095KB, committed=2268079KB
-                 Java Heap (reserved=2097152KB, committed=2097152KB)
                            (mmap: reserved=2097152KB, committed=2097152KB) 
 
-                     Class (reserved=1080888KB, committed=34744KB)
                            (classes #4759)
                            (malloc=5688KB #6157) 
                            (mmap: reserved=1
                            075200KB, committed=29056KB) 
 
-                    Thread (reserved=24841KB, committed=24841KB)
                            (thread #25)
                            (stack: reserved=24672KB, committed=24672KB)
                            (malloc=77KB #126) 
                            (arena=92KB #48)
 
-                      Code (reserved=251579KB, committed=12707KB)
                            (malloc=1979KB #3139) 
                            (mmap: reserved=249600KB, committed=10728KB) 
 
-                        GC (reserved=82398KB, committed=82398KB)
                            (malloc=5774KB #176) 
                            (mmap: reserved=76624KB, committed=76624KB) 
 
-                  Compiler (reserved=161KB, committed=161KB)
                            (malloc=30KB #127) 
                            (arena=131KB #3)
 
-                  Internal (reserved=6316KB, committed=6316KB)
                            (malloc=6284KB #6509) 
                            (mmap: reserved=32KB, committed=32KB) 
 
-                    Symbol (reserved=8528KB, committed=8528KB)
                            (malloc=5483KB #50107) 
                            (arena=3045KB #1)
 
-    Native Memory Tracking (reserved=1045KB, committed=1045KB)
                            (malloc=5KB #64) 
                            (tracking overhead=1040KB)
 
-               Arena Chunk (reserved=187KB, committed=187KB)
                            (malloc=187KB) 



DescriptionThis KB helps administrators to identify how JVMs utilize internal memory beyond heap, which helps explain why applications consume more memory than expected.
Product

Last modified on Jan 18, 2019

Was this helpful?

Yes
No
Provide feedback about this article
Powered by Confluence and Scroll Viewport.