This topic describes how metrics related to Java virtual machine (JVM) memory, GC, threads, classes, and file descriptors are collected.
Memory metrics
The ARMS agent has a scheduled task that periodically calls the JDK interface java.lang.management.ManagementFactory#getPlatformMXBeans(java.lang.Class<T>) with the parameter java.lang.management.MemoryPoolMXBean.class to obtain memory metrics.
This method returns a list where each object in the list reflects the expected memory usage of different memory spaces in the JVM. The following code snippet demonstrates how to use this method.
public static void printCurrentJVMMemoryUsage() {
List<MemoryPoolMXBean> beans = ManagementFactory.getPlatformMXBeans(MemoryPoolMXBean.class);
for (MemoryPoolMXBean bean : beans) {
System.out.printf("area=%s\tname=%s\tinitial=%d\tmax=%d\tcommited=%d\tuse=%d\n", bean.getType().name(),
bean.getName(), bean.getUsage().getInit(), bean.getUsage().getMax(), bean.getUsage().getCommitted(), bean.getUsage().getUsed());
}
}The output of this code snippet may vary across different JVM versions. A possible output is shown as follows, which includes the type, name, initial size, maximum size, committed size, and used size of each memory space.
area=NON_HEAP name=Code Cache initial=2555904 max=134217728 commited=3211264 use=3139712
area=NON_HEAP name=Metaspace initial=0 max=-1 commited=8388608 use=7950584
area=NON_HEAP name=Compressed Class Space initial=0 max=1073741824 commited=1048576 use=919408
area=HEAP name=PS Eden Space initial=67108864 max=1409286144 commited=67108864 use=39057856
area=HEAP name=PS Survivor Space initial=11010048 max=11010048 commited=11010048 use=0
area=HEAP name=PS Old Gen initial=179306496 max=2863661056 commited=179306496 use=0The ARMS agent periodically collects this data, and upon collection, it directly reports and records these metrics without any additional processing, as detailed in the following table.
Metric | Description |
arms_jvm_mem_init_bytes | The initial memory size. |
arms_jvm_mem_max_bytes | The maximum memory size. |
arms_jvm_mem_committed_bytes | The committed memory size. |
arms_jvm_mem_used_bytes | The used memory size. |
The following table describes two key dimensions.
Dimension | Description | Example |
area | The memory space type. | heap, nonheap |
id | The memory space name. | eden, survivor, total |
For information about JVM memory spaces, see JVM memory details.
GC metrics
Agents earlier than V4.4.0: Metrics are retrieved by a scheduled task that periodically calls the JDK interface
java.lang.management.ManagementFactory#getPlatformMXBeans(java.lang.Class<T>)and passes thejava.lang.management.GarbageCollectorMXBeanparameter.Agents V4.4.0 and later: Metrics are retrieved by subscribing to the
GarbageCollectionNotificationInfoevent ofGarbageCollectionNotificationInfo.
This method returns a list where each object in the list reflects the status of different garbage collectors in the JVM. The following code snippet demonstrates how to use this method.
public static void printGC() {
List<GarbageCollectorMXBean> beans = ManagementFactory.getPlatformMXBeans(GarbageCollectorMXBean.class);
for (GarbageCollectorMXBean bean : beans) {
System.out.printf("name=%s\tgcCount=%d\tgcTime=%d\n", bean.getName(),
bean.getCollectionCount(), bean.getCollectionTime());
}
}The output of this code snippet may vary across different JVM versions. A possible output is shown as follows, which includes the name of each garbage collector, the number of garbage collection (GC) occurrences, and the GC time consumed.
name=PS Scavenge gcCount=0 gcTime=0
name=PS MarkSweep gcCount=0 gcTime=0Note that, since this data records cumulative values since the JVM was started, after periodically collecting this data, the ARMS agent subtracts the value obtained from the previous collection to calculate the number of GC occurrences and the GC time consumed within the current period (default 15 seconds). It then reports and records these metrics as described in the following table.
Z garbage collector (ZGC) and Shenandoah:
Pauses: stop-the-world (STW) duration, typically shorter than 1 ms
Cycles: total duration for a GC
Others: Latency metrics exclusively measure the STW duration, that is, when all Java application threads are suspended for GCs.
Metric | Description |
arms_jvm_gc_delta | The number of GC occurrences in the current cycle. |
arms_jvm_gc_seconds_delta | The GC time consumed in the current cycle. |
Considering the variety of actual garbage collectors, to reduce user comprehension costs, the ARMS agent maps the actual garbage collector names to "Young" and "Old," and records them in the dimensions listed in the following table.
Dimension | Description | Example |
gen | The GC type. | young, old |
cause | The GC trigger, supported in agents V4.4.0 and later. | System.gc(), Heap Dump Initiated GC, Allocation Failure |
The following table describes the mapping relationships.
Garbage collector name | Gen value |
Copy | young |
G1 Young Gen | young |
G1 Old Gen | old |
G1 Young Generation | young |
G1 Old Generation | old |
ParNew | young |
ConMarkSweep | old |
ConcurrentMarkSweep | old |
PS Scavenge | young |
PS MarkSweep | old |
PS Serial | young |
MarkSweepCompact | old |
Due to significant changes in the overall GC design in the latest Z Garbage Collector (ZGC), the previous simple classification methods like YoungGC and FullGC are no longer applicable. ZGC is mapped separately as follows.
Garbage collector name | Gen value |
ZGC Cycles | cycles |
ZGC Pauses | pauses |
ZGC Minor Cycles | young_cycles |
ZGC Minor Pauses | young_pauses |
ZGC Major Cycles | old_cycles |
ZGC Major Pauses | old_pauses |
Note that the ARMS console displays a chart called "Thread Stack Usage," as shown in the figure below. This metric is not collected on the ARMS agent; it is calculated by multiplying the current number of live threads by 1MB. By default, the JVM allocates 1MB of space for each thread to store information such as the local variable table, operand stack, dynamic links, and method return addresses within stack frames.

Thread metrics
The ARMS agent has a scheduled task that periodically calls the JDK interface java.lang.management.ManagementFactory#getThreadMXBean to obtain thread metrics.
This method returns an instance of type java.lang.management.ThreadMXBean, which reflects the current JVM thread situation. The following code snippet demonstrates how to use this method.
public static void printThreads() {
ThreadMXBean threadMXBean = java.lang.management.ManagementFactory.getThreadMXBean();
int threadCount = threadMXBean.getThreadCount();
int daemonThreadCount = threadMXBean.getDaemonThreadCount();
long totalStartedThreadCount = threadMXBean.getTotalStartedThreadCount();
long terminatedThreadCount = totalStartedThreadCount - threadCount;
System.out.printf("allStartedThreadCount=%d\tcurrentThreadCount=%d\tdaemonThreadCount=%d\tterminatedThreadCount=%d\n"
, totalStartedThreadCount, threadCount, daemonThreadCount, terminatedThreadCount);
}The output of this code snippet may vary across different JVM versions. A possible output is shown as follows, which includes the cumulative number of threads started, the number of live threads, the number of daemon threads, and the cumulative number of terminated threads in the current JVM. Noted that, except for the cumulative number of terminated threads, the other thread counts are obtained directly by calling the ThreadMXBean method. The cumulative number of terminated threads is calculated by subtracting the current number of live threads from the cumulative number of threads started, representing the total number of threads that have completed their tasks and been terminated since the JVM was launched.
allStartedThreadCount=5 currentThreadCount=5 daemonThreadCount=4 terminatedThreadCount=0Additionally, for the number of currently live threads, the agent will separately count the number of threads in each of the following states: RUNNABLE, BLOCKED, WAITING, and TIMED_WAITING.
The ARMS agent periodically collects this data, and after collection, it directly records these metrics without any additional processing, as detailed in the following table.
Metric | Description |
arms_jvm_threads_count | The initial memory size. |
The different threads mentioned above are distinguished by the following key dimensions.
Dimension | Description | Example |
state | The thread status. |
For live threads, the following different states are counted separately.
|
Class metrics
The ARMS agent has a scheduled task that periodically calls the JDK interface ManagementFactory.getClassLoadingMXBean() to obtain class loading metrics.
This method returns an instance of type java.lang.management.ClassLoadingMXBean, which reflects the current JVM class situation. The following code snippet demonstrates how to use this method.
public static void printCurrentJVMMemoryUsage() {
ClassLoadingMXBean classLoaderMXBean = ManagementFactory.getClassLoadingMXBean();
long totalLoadedClassCount = classLoaderMXBean.getTotalLoadedClassCount();
long unloadedClassCount = classLoaderMXBean.getUnloadedClassCount();
System.out.printf("totalLoadedClassCount=%d\tunloadedClassCount=%d\n"
, totalLoadedClassCount, unloadedClassCount);
}The output of this code snippet may vary across different JVM versions. A possible output is shown as follows, which includes the cumulative number of classes loaded and the cumulative number of classes unloaded by the current JVM.
totalLoadedClassCount=1355 unloadedClassCount=0Note that, since this data records cumulative values since the JVM was started, after periodically collecting this data, the ARMS agent subtracts the value obtained from previous collection to calculate the number of classes loaded and unloaded within the current period (default 15 seconds). It then reports and records these metrics as described in the following table.
Metric | Description |
arms_class_load_loaded | The number of classes loaded in the current cycle. |
arms_class_load_un_loaded | The number of classes unloaded in the current cycle. |
File descriptor metrics
The ARMS agent has a scheduled task that periodically calls the JDK interface ManagementFactory.getOperatingSystemMXBean() to obtain file descriptor metrics.
This method returns an instance of type java.lang.management.OperatingSystemMXBean, which reflects the open file descriptor of the current JVM. The following code snippet demonstrates how to use this method.
public static void printFDUsage() {
OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
if (!(operatingSystemMXBean instanceof UnixOperatingSystemMXBean)) {
return;
}
long openFDCount = ((UnixOperatingSystemMXBean) operatingSystemMXBean).getOpenFileDescriptorCount();
long maxFDCount = ((UnixOperatingSystemMXBean) operatingSystemMXBean).getMaxFileDescriptorCount();
System.out.printf("openFDCount=%d\tfdOpenRatio=%f\n"
, openFDCount, (double) openFDCount / maxFDCount);
}The output of this code snippet may vary across different JVM versions. A possible output is shown as follows, which includes the number of open file descriptors and the file descriptor open rate for the current JVM. The file descriptor open rate is calculated by dividing the number of currently open file descriptors by the total number of file descriptors that the current JVM can open.
openFDCount=184 fdOpenRatio=0.017969The ARMS agent periodically collects this data, and after collection, it directly records these metrics without any additional processing, as detailed in the following table.
Metric | Description |
arms_file_desc_open_count | The number of file descriptors opened by the current JVM. |
arms_file_desc_open_ratio | The number of classes unloaded in the current cycle. |