虛擬機性能監控與故障處理 — 兩個可視化工具 — JVM系列(十二)

一、前言

JDK中除了提供大量的命令行工具外,還有兩個功能強大的可視化工具Jconsole和VisualVM。

二、Jconsole

Jconsole是一種基於JMX的可視化監視、管理工具,它管理部分的功能是針對JMX MBean進行管理,我們主要關注的是Jconsole的監控部分的功能。

Jconsole既可以監控本地進程,也可以連接遠程的服務器。

我們打開JDK中的Jconsole,然後選擇想要監控的進程就可以了。

Jconsole的主界面包括以下6個標籤:

  • 概述:包括了堆內存使用情況、線程、類、CPU使用情況4種信息的曲線圖。
  • 內存:相當於可視化的jstat命令,用來監視受收集器管理的虛擬機內存(Java堆和永久代)的變化趨勢。
  • 線程:相當於可視化的jstack命令,遇到線程停頓時可以使用這個頁籤進行監控分析,可能是等待外部資源,循環或者鎖等待的原因。可以檢測死鎖的情況。
  • VM摘要
  • MBean

三、VisualVM

目前爲止,隨着JDK發佈的功能最強大的運行監視和故障處理程序。

同時VisualVM還有性能分析的功能,它的性能分析功能比JProfile等專業收費的工具也不會遜色。

因爲VisualVM不需要被監視的程序基於特殊的Agent運行,因此它對應用程序的實際性能影響很小,可以直接用在生產環境中。

VisualVM具有插件擴展的功能,可以安裝很多的插件。

VisualVM可以做到:

  • 顯示虛擬機進程以及進程的配置、環境信息(jps、jinfo)。
  • 監視應用程序的CPU、GC、堆、方法區以及線程的信息(jstat、jstack)。
  • dump以及分析堆轉儲快照(jmap、jhat)。
  • 方法級的程序運行性能分析,找出被調用最多、運行時間最長的方法。
  • 離線程序快照:收集程序的運行時配置、線程dump、內存dump等信息建立一個快照,可以將快照發送開發者處進行Bug反饋。
  • 其他plugins的無限的可能性。

1、如何dump堆和線程

我們可以進行堆的dump或者線程的dump,然後會在對應的進程下面直接生成這兩個文件,但是如果需保存的話,需要將其另存爲,同時後期想要繼續分析dump文件的話,可以通過裝入功能引入dump文件。

在這裏插入圖片描述
我們可以在堆的dump文件的摘要面板上看到dump時的運行時參數、System.getProperties( )內容,線程堆棧等信息。

2、類面板

類面板可以看到以類爲統計口徑的統計類的實例數量、容量信息。

在這裏插入圖片描述

3、實例面板

實例面板不能直接使用,因爲不能確定用戶想看哪個類的實例,所以需要通過類面板進入。

4、Profiler的使用

在Profiler頁籤中,VisualVM提供了程序運行期間方法級的CPU執行時間分析以及內存分析,做Profiling分析肯定對程序運行性能有比較大的影響,所以一般不在生產環境中使用這項功能。

首先選擇CPU和內存按鈕中的一個,然後切換到應用程序對程序進行操作,VisualVM會記錄到這段時間中應用程序執行過的方法。

如果是CPU分析,將會統計每個方法的執行次數、執行耗時。

如果是內存分析,則會統計每個方法關聯的對象數以及這些對象所佔的空間。

分析結束後,點擊停止按鈕結束監控過程。

5、BTrace的使用

BTrace是一個很有趣的VisualVM插件,本身也是可以獨立運行的程序。

它的作用是在不停止目標程序運行的前提下,通過虛擬機的HotSwap技術動態加入原本不存在的調試代碼。

這項功能對實際生產中的程序很有意義,可以在不停服務的情況下,方便添加日誌,進而排查問題。

我們安裝完BTrace插件後,在應用程序面板中右鍵點擊要調試的程序,會出現Trace Application菜單,點擊進入BTrace面板。

在這裏插入圖片描述

這個面板裏面看起來就像一個簡單的Java程序開發環境,裏面還有一段Java代碼,如下圖所示:

在這裏插入圖片描述

我們通過一個程序的例子,源代碼如下:

package com.example.demo.jvm;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

// 產生兩個1000以內的隨機整數,輸出這兩個數字相加的結果
public class BTraceTest {

	public int add(int a, int b) {
		return a + b;
	}

	public static void main(String[] args) throws IOException {
		BTraceTest test = new BTraceTest();
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		for (int i = 0; i < 10; i++) {
			reader.readLine();
			int a = (int) Math.round(Math.random() * 1000);
			int b = (int) Math.round(Math.random() * 1000);
			System.out.println(test.add(a, b));
		}
	}
}

我們把以上的程序運行後,我們在VisualVM中打開該程序的監視,在BTrace頁填充TracingScript的內容,程序如下所示:

/* BTrace Script Template */
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;

@BTrace
public class TracingScript {
    /* put your code here */
    @OnMethod(
            clazz = "com.example.demo.jvm.BTraceTest",
            method = "add",
            location = @Location(Kind.RETURN)
    )

    public static void func(@Self com.example.demo.jvm.BTraceTest instance, int a, int b, @Return int result) {
        println("調用堆棧:");
        jstack();
        println(strcat("方法參數A:", str(a)));
        println(strcat("方法參數B:", str(b)));
        println(strcat("方法結果:", str(result)));
    }
}

點擊Start按鈕稍等片刻,編譯完成後,可見Output面板中出現BTrace code successfuly deployed的字樣,程序運行的時候在Output面板將會輸出如下圖所示的調試信息。

在這裏插入圖片描述

BTrace的用法還有很多,打印調用堆棧、參數、返回值只是最基本的應用,在它的網站上有使用BTrace進行性能監視、定位連接泄漏、解決多線程競爭問題等的例子。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章