全部產品
Search
文件中心

Application Real-Time Monitoring Service:JVM 指標說明

更新時間:Jun 06, 2025

本文介紹了JVM記憶體、GC、線程、類、檔案控制代碼等指標的採集原理。

記憶體相關指標

ARMS探針中存在一個定時任務,通過定期調用JDK的介面 java.lang.management.ManagementFactory#getPlatformMXBeans(java.lang.Class<T>)並傳入 java.lang.management.MemoryPoolMXBean.class參數獲得JVM記憶體相關指標。

該方法會返回一個列表,列表中每一個對象反映了JVM中不同記憶體預期使用方式。下面的程式碼片段簡單地示範了如何使用該方法。

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());
    }
}

該程式碼片段在不同JVM版本中的輸出有所不同,一個可能的輸出結果如下所示,包含了每一個記憶體地區的類型,名稱以及初始大小、最大大小、已提交量和已使用量。

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=0

ARMS探針定期採集這些資料,採集到後不做任何額外加工直接上報並記錄在下述指標中。

指標名

指標含義

arms_jvm_mem_init_bytes

記憶體初始大小

arms_jvm_mem_max_bytes

記憶體最大大小

arms_jvm_mem_committed_bytes

記憶體已提交大小

arms_jvm_mem_used_bytes

記憶體已使用大小

其中兩個關鍵維度:

維度名稱

維度含義

維度舉例

area

記憶體地區類型

heap、nonheap

id

記憶體地區名稱

eden、survivor、total

JVM各個記憶體地區說明請參見JVM監控記憶體詳情說明

GC相關指標

針對4.4.0以下版本探針,ARMS探針中存在一個定時任務,通過定期調用JDK的介面 java.lang.management.ManagementFactory#getPlatformMXBeans(java.lang.Class<T>)並傳入 java.lang.management.GarbageCollectorMXBean參數獲得JVM GC相關指標;針對4.4.0及以上版本探針,通過訂閱由 GarbageCollectorMXBean提供的 GarbageCollectionNotificationInfo事件擷取相關資料。

該方法會返回一個列表,列表中每一個對象反映了JVM中不同垃圾收集器的運行情況。下面的程式碼片段簡單地示範了如何使用該方法。

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());
    }
}

該程式碼片段在不同JVM版本中的輸出有所不同,一個可能的輸出結果如下所示,包含了每一個記憶體回收行程的名稱、GC次數以及GC耗時。

name=PS Scavenge	gcCount=0	gcTime=0
name=PS MarkSweep	gcCount=0	gcTime=0

需要注意的是,因為該資料記錄的是JVM啟動以來的累計值,ARMS探針在定期採集到這些資料後會減去上一次採集的值得到當前周期(預設15秒)內的GC次數和GC耗時,然後上報並記錄在下述指標中。

說明

除了ZGC和Shenandoah類型的GC外,其他類型的GC耗時都是指Stop the world(STW,即GC過程中暫停所有Java業務線程的執行)耗時。在ZGC和Shenandoah中,Pauses對應STW耗時,Cycles表示一次GC的總耗時。

指標名

指標含義

arms_jvm_gc_delta

當前周期GC次數

arms_jvm_gc_seconds_delta

當前周期GC耗時

考慮到實際的記憶體回收行程數量較多,為降低使用者理解成本, ARMS探針會將實際的記憶體回收行程名稱映射為Young和Old並記錄在下述維度中。

維度名稱

維度含義

維度舉例

gen

GC類型

young、old

cause

GC觸發原因(4.4.0及以上版本探針支援)

System.gc()、Heap Dump Initiated GC、Allocation Failure等。

展開查看詳細的維度說明

  • System.gc():當程式顯式調用System.gc()請求進行記憶體回收時,會觸發此原因。

  • FullGCAlot / ScavengeAlot:這些原因可能與測試或調試情境有關,其中頻繁的完整GC或小型GC(“清除”)被故意觸發。

  • Allocation Profiler:此記憶體回收原因可能涉及記憶體配置分析,以更好地理解記憶體使用量情況。

  • JvmtiEnv ForceGarbageCollection:表示Java虛擬機器工具介面(JVMTI)發出了強制記憶體回收的請求。

  • Heap Inspection Initiated GC & Heap Dump Initiated GC:這些通常不是常規操作,但用於檢查堆或擷取堆轉儲。

  • WhiteBox Initiated Young/Full GC & Run to Breakpoint:這些由WhiteBox測試引發,通常用於JVM自我裝載目的。

  • No GC:表示沒有進行記憶體回收的情境。

  • Allocation Failure:因為JVM無法為新對象分配記憶體而觸發的記憶體回收,表明可能存在記憶體壓力情況。

  • CodeCache GC Threshold / Aggressive:涉及代碼緩衝,它儲存編譯後的代碼。當緩衝達到某個閾值或需要積極管理時,可能會觸發GC。

  • Metadata GC Threshold / Clear Soft References:由中繼資料空間閾值或軟引用清除觸發的GC,可以在不影響應用程式執行的情況下釋放記憶體。

  • G1 Evacuation Pause / Compaction Pause / Humongous Allocation / Periodic Collection:這些是與G1垃圾收集器相關的特定GC原因,它針對低暫停時間進行了最佳化。

  • Diagnostic Command:通過診斷命令觸發,通常用於內部監控或診斷目的。

  • Shenandoah GC Causes:這些與Shenandoah垃圾收集器有關,該收集器旨在通過並行作業減少暫停時間。

  • Z Garbage Collector Causes (Timer, Warmup, etc.):這些特定於ZGC(Z垃圾收集器),重點在於效能調優方面,例如熱身、分配率和主動措施。

  • ILLEGAL VALUE:表示非法或未識別的記憶體回收原因值,作為對意外情況的保護措施。

具體的映射關係如下:

記憶體回收行程名稱

Gen取值

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

由於在最新的ZGC中,整體GC的設計有較大變動,不再適用之前簡單的YoungGC、FullGC這種分類方式,ZGC單獨映射如下:

記憶體回收行程名稱

Gen取值

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

需要注意,在ARMS控制台上會展示一個叫做線程棧使用的圖表,如下圖所示,該指標並非在ARMS探針側採集,是通過當前存活線程數 × 1MB計算所得。JVM中預設會為每個線程分配1MB的空間用於儲存棧幀中的局部變數表、運算元棧、動態連結和方法返回地址等資訊。

image.png

線程相關指標

ARMS探針中存在一個定時任務,通過定期調用JDK的介面 java.lang.management.ManagementFactory#getThreadMXBean獲得JVM線程相關指標。

該方法會返回一個類型為java.lang.management.ThreadMXBean的執行個體,該執行個體反映了當前JVM的線程情況。下面的程式碼片段簡單地示範了如何使用該方法。

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);
}

該程式碼片段在不同JVM版本中的輸出有所不同,一個可能的輸出結果如下所示,包含了當前JVM累計啟動的線程數、存活的線程數、後台線程數以及累計的終結線程數。需要注意,除了終結線程數之外,其餘幾個線程數均是通過直接調用ThreadMXBean方法獲得,累計的終結線程數是通過累計啟動線程數減去當前存活線程數獲得,代表了從JVM啟動後,累計有多少線程完成執行任務而被終結回收。

allStartedThreadCount=5	currentThreadCount=5	daemonThreadCount=4	terminatedThreadCount=0

此外對於當前存活的線程數,會分別統計其處於RUNNABLE、BLOCKED、WAITING、TIMED_WAITING的線程數量。

ARMS探針會定期採集這些資料,採集後不做額外處理直接記錄在下述指標中。

指標名

指標含義

arms_jvm_threads_count

記憶體初始大小

上文提到的不同線程通過下述關鍵維度區分。

維度名稱

維度含義

維度舉例

state

線程狀態

  • live:當前存活線程數

  • daemon:守護線程數

  • terminated:終結線程數,僅 4.x 探針支援。

對於live線程,會分別統計下述不同狀態的線程數:

  • new:建立狀態

  • runnable:可運行狀態

  • blocked:阻塞狀態

  • wait:等待狀態

  • timed-wait:有逾時時間的的等待狀態

類相關指標

ARMS探針中存在一個定時任務,通過定期調用JDK的介面 ManagementFactory.getClassLoadingMXBean()獲得JVM類載入相關指標。

該方法會返回一個類型為java.lang.management.ClassLoadingMXBean的執行個體,該執行個體反映了當前JVM的線程情況。下面的程式碼片段簡單地示範了如何使用該方法。

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);
}

該程式碼片段在不同JVM版本中的輸出有所不同,一個可能的輸出結果如下所示,包含了當前JVM累計載入的類數量和累計卸載的類數量。

totalLoadedClassCount=1355	unloadedClassCount=0

需要注意,因為該資料記錄的是JVM啟動以來的累計值,ARMS探針在定期採集到這些資料後會減去上一次採集的值得到當前周期(預設15秒)內的類載入數量和類卸載數量,然後上報並記錄在下述指標中。

指標名

指標含義

arms_class_load_loaded

當前周期載入類數量

arms_class_load_un_loaded

當前周期卸載類數量

檔案控制代碼相關指標

ARMS探針中存在一個定時任務,通過定期調用JDK的介面 ManagementFactory.getOperatingSystemMXBean()獲得JVM類載入相關指標。

該方法會返回一個類型為java.lang.management.OperatingSystemMXBean的執行個體,該執行個體反映了當前JVM的檔案控制代碼開啟情況。下面的程式碼片段簡單地示範了如何使用該方法。

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);
}

該程式碼片段在不同的JVM版本輸出有所不同,一個可能的輸出結果如下所示,結果中輸出了當前JVM開啟的檔案控制代碼數和檔案控制代碼開啟率,檔案控制代碼開啟率是由當前JVM已經開啟的檔案控制代碼數除以當前JVM總的可開啟檔案控制代碼數得到。

openFDCount=184	fdOpenRatio=0.017969

ARMS 探針會定期採集這些資料,採集後不做額外處理直接記錄在下述指標中。

指標名

指標含義

arms_file_desc_open_count

當前JVM開啟的檔案控制代碼數

arms_file_desc_open_ratio

當前周期卸載類數量