Java虛擬機(Java Virtual Machine,JVM)是一種可以執行Java字節碼的虛擬機,它是Java平臺的核心組成部分之一。JVM負責將Java字節碼翻譯成特定平臺上的機器指令,使得Java程序可以在各種不同的平臺上運行。
JVM監控即Java虛擬機監控,用于監控重要的JVM指標。

- JVM內存包括堆(heap)內存、非堆(non-heap)內存。堆內存用于存儲對象實例,而非堆內存用于存儲Java虛擬機自身使用的數據和代碼等。
- 非堆內存包括直接內存中的元空間(sdk1.8用的元空間,sdk1.7用的是線程共享的方法區)、線程私有的虛擬機棧、程序計數器、本地方法棧。
- 堆的釋放受到GC垃圾回收器的管理,GC會去找那些很久沒有引用地址指向的內存塊,把它們清理掉。
說明JVM相關數據采集間隔為15s一次,采集的是瞬時值中的最大值,總數由多個數據加和而成。以堆內存圖表為例,1分鐘內我們分別采集了老年代、年輕代各4次,取其中的最大值展示,總和為最大值之和(因此總和可能大于用戶配置的jvm內存大小)。
功能入口
- 選擇目標資源池,并登錄APM組件控制臺。
- 在左側導航欄中選擇「應用監控」-「應用列表」。
- 在應用列表中選擇您想查看的應用,點擊「應用名稱」打開新的應用詳情鏈接。
- 在左側導航欄中選擇「應用詳情」,您可以在應用詳情頁面切換至「JVM監控」頁簽,在左側關鍵指標中選擇不同的應用實例,可查看該應用實例相應的概覽信息。
功能說明
內存
堆內存詳情
堆內存用于存儲對象實例,包含1/3的新生代和2/3的老年代。
- 新生代:是用來存放新生的對象。 分為Eden 區、 SurvivorFrom、 SurvivorTo 三個區。Minor GC進行垃圾回收。JVM 每次只會使用 Eden 和其中的一塊 Survivor 區域來為對象服務,新生代實際可用的內存空間為 9/10 ( 即90% )的新生代空間。
- Eden 區 :Java 新對象的出生地(如果新創建的對象占用內存很大,則直接分配到老年代)。當 Eden 區內存不夠的時候就會觸發 Minor GC,對新生代區進行一次垃圾回收。Servivor區不會觸發Minor GC。
- ServivorFrom 區:上一次 GC 的幸存者,作為這一次 GC 的被掃描者。
- ServivorTo 區:保留了一次 MinorGC 過程中的幸存者。
- 老年代:主要存放應用程序中生命周期長的內存對象。 Major GC進行垃圾回收。可能會拋出OOM(Out Of Memory)異常
非堆內存
非堆內存用于存儲Java虛擬機自身使用的數據和代碼等等。提交字節數、初始字節數和最大字節數是指非堆內存的三個重要參數,具體含義如下
- 提交字節數(Committed Bytes):指已經被操作系統分配給Java虛擬機的非堆內存大小,包括已經使用的和未使用的部分,是在Java虛擬機運行時動態確定的。
- 初始字節數(Initial Bytes):指Java虛擬機啟動時申請的非堆內存大小,也就是Java虛擬機最初分配的非堆內存大小。
- 最大字節數(Max Bytes):指Java虛擬機能夠申請的非堆內存的最大值。當Java虛擬機需要更多的非堆內存時,可以向操作系統請求更多的內存,直到達到最大字節數為止。
這些指標可以用來觀察非堆內存的大小變化,以便我們根據具體的應用程序調整非堆內存的參數設置(例如使用“-XX:MaxDirectMemorySize”參數來設置非堆內存的最大字節數等等),以保證應用程序能夠正常運行,并且不會造成不必要的內存浪費。
元空間詳情
- 元空間(Metaspace):是JDK1.8及以上版本引入的概念,用來替代了永久代(PermGen)的概念。元空間主要用來存儲class的元數據信息,包括類的名稱、父類、接口、字段、方法等信息。元空間不再像永久代那樣有固定的大小,而是使用本地內存來存儲元數據。通過設置元空間大小參數,可以控制元空間的大小。當元空間不足時,JVM會自動擴容。元空間的大小僅受本地內存限制。
說明永久代(PermGen)是JDK1.7及以下版本中的概念,用來存儲類信息和常量池。永久代的大小是固定的,由JVM啟動時指定。當永久代空間不足時,會導致OutOfMemoryError異常。
直接緩沖區
直接緩沖區(Direct Buffer)通常也稱為直接內存(Direct Memory),它是一種可以直接訪問操作系統內存空間的緩沖區。與普通的Java NIO緩沖區不同,直接緩沖區不需要將數據從Java堆內存復制到直接內存,而是直接將數據存儲在直接內存中,從而避免了數據拷貝的開銷,提高了IO操作的效率。
- DirectBuffer總大小:指已經被Java虛擬機分配的所有DirectBuffer緩沖區的總大小,包括已經使用的和未使用的部分。
- DirectBuffer使用大小:指當前正在被使用的DirectBuffer緩沖區的總大小。
DirectBuffer總大小和使用大小都是在運行時動態確定的。這些指標可以用來判斷直接緩沖區的使用情況。由于直接內存不受Java虛擬機的垃圾回收機制控制,所以如果不及時釋放直接內存,可能會導致內存泄漏或者OutOfMemoryError等問題。因此,我們需要關注直接內存的使用情況,以便及時釋放不再需要的內存空間,可以使用ByteBuffer的cleaner()方法或者手動調用System.gc()方法來釋放直接內存。
GC
GC累計次數與GC瞬時次數
提供累計/瞬時兩種視角查看。
- OldGC次數:指的是Java虛擬機中的老年代垃圾回收次數。它主要處理老年代中不再使用的對象。
- YoungGC次數:指的是Java虛擬機中的新生代垃圾回收次數。它主要處理新生代中不再使用的對象。
GC累計耗時與GC瞬時耗時
提供累計/瞬時兩種視角查看。
- OldGC耗時:指的是Java虛擬機中的老年代垃圾回收累計花費的時間。
- YoungGC耗時:指的是Java虛擬機中的新生代垃圾回收累計花費的時間。
線程
線程(Thread)是操作系統能夠進行運算調度的最小單位,是程序執行的基本單元。在Java中,每個線程都是一個獨立的執行路徑,它可以獨立地執行代碼、訪問變量和資源,與其他線程并發執行。
JVM線程數
JVM線程數是指在Java虛擬機中活躍的線程數,也就是當前正在執行的Java線程數量,包括用戶線程(比如計算、IO操作等等)和守護線程(比如垃圾回收、內存監控等等)。
- 線程總數:指當前Java虛擬機中的線程總數,包括用戶線程和守護線程。
- 阻塞線程數:指當前因為等待某些條件而被阻塞的線程數量,例如等待IO操作完成、等待鎖釋放等。
- 死鎖線程數:指當前處于死鎖狀態的線程數量,即兩個或多個線程相互等待對方釋放資源,從而導致所有線程都無法繼續執行。
- 新建線程數:指當前正在創建的線程數量,這些線程尚未開始執行任何任務。
- Runnable線程數(可運行線程數):指當前處于可運行狀態的線程數量,這些線程已經準備好被調度執行,但是可能還沒有得到CPU的時間片。
- 終結線程數:指已經被終止但是還沒有被垃圾回收的線程數量,這些線程的run()方法已經執行完畢,但是線程對象還沒有被回收。
- Timed_Waiting的線程數(限時等待線程數):指當前正在等待一段時間后才能繼續執行的線程數量,例如使用Thread.sleep()方法或Object.wait(long)方法進行限時等待的線程數量。
- Waiting的線程數(等待中線程數):指當前正在等待某些條件而被掛起的線程數量,例如使用Object.wait()方法進行無限等待的線程數量。
這些指標可以用來監控Java虛擬機中線程狀態的變化,以及分析線程運行情況和性能瓶頸。
JVM類總數
- 已加載類總數:指的是當前已經被Java虛擬機(JVM)加載的類的總數。當JVM加載一個類時,它會對該類進行解析、驗證和準備,并將其放入方法區(或稱為永久代或元空間,具體取決于JVM的版本和配置)。已加載類總數表示了在JVM啟動以來,已經成功加載到內存中的類的數量。
- 已卸載類總數:指的是從JVM中卸載(或稱為卸載垃圾收集)的類的總數。在某些情況下,JVM可能會卸載已加載的類,例如當類的實例被垃圾收集器判定為不再可達時。已卸載類總數表示自JVM啟動以來被卸載的類的數量。
- 當前加載類總數:指的是當前在JVM中仍然保留的已加載類的數量。它包括尚未被卸載的類以及仍然被JVM使用的類。這個數字可以隨著應用程序的進行而變化,因為新的類可以被動態地加載到JVM中,而一些不再使用的類可以被卸載。
統一交互操作說明:
- 將光標移到統計圖上,可以查看光標所至時間點的數據詳情。
- 單擊
圖標,可以將當前圖表放大顯示。