VisualVM(All-in-One Java Troubleshooting Tool)是功能最強大的運作監視和故障處理程式之一,它內建了多種性能統計工具的功能,可以替代jstat,jmap,jstack,也可以替代JConsole的使用。VisualVM有一個很大的優點:不需要被監視的程式基于特殊的Agent去運作,是以它的通用性很強,對應用程式實際性能的影響也較小,使得它可以直接應用在生産環境中。
還有一大特點就是支援插件擴充,有了插件的擴充能力,就可以支援更多的功能,例如
- 顯示虛拟機程序以及程序的配置、環境資訊(jps、jinfo)。
- 監視應用程式的處理器、垃圾收集、堆、方法區以及線程的資訊(jstat、jstack)。
- dump以及分析堆轉儲快照(jmap、jhat)。
- 方法級的程式運作性能分析,找出被調用最多、運作時間最長的方法。
- 離線程式快照:收集程式的運作時配置、線程dump、記憶體dump等資訊建立一個快照,可以将快照發送開發者處進行Bug回報。
打開并連接配接
程式是在%JAVA_HOME%/bin的目錄下,直接輕按兩下即可啟動用戶端,如下圖
此監控工具預設的功能較少,我們首先要安裝一些插件,友善我們監控使用,點選
工具
->
插件
打開插件的安裝頁面,并選擇自己需要的插件下載下傳即可,如下
如果下載下傳不了,請重新設定插件中心配置
根據自己的jdk版本在插件中心頁面找到對應版本的位址,然後點選進入,最上面的Catalog URL就是需要的配置中心位址:visualvm.github.io/pluginscent…
和Jconsole一樣,有兩種連接配接方式,一個是本地連接配接,另一個是遠端連接配接
本地連接配接:在控制台可以看到本地出現的Java程式,直接輕按兩下或者右鍵打開 即可
遠端連接配接:右鍵選擇JMX連接配接,輸入連接配接資訊IP:端口 點選确定即可(本地節點會下出現一個jmx的圖示)前提是Java程式已經添加以下參數啟動
-Djava.rmi.server.hostname=127.0.0.1 //遠端伺服器的IP(本地可通路)
-Dcom.sun.management.imxremote
-Dcom.sun.management.jmxremote.port=5555 // 遠端伺服器的端口(随便定一個,用于JMX管理該程序)
-Dcom.sun.management.jmxremote.authenticate=false // 是否驗證(true的話需要配置密碼,自行百度吧)
-Dcom.sun.management.jmxremote.ssl=false //ssl控制
如下兩個相同的應用,一個是遠端的連接配接,一個是本地的連接配接
應用概述
這個概述tab可以檢視應用的基本資訊,例如java版本,主類,jvm參數(啟動參數),系統屬性等
監控資訊
切換到監控tab 可以看到應用的CPU,堆,元空間,類加載以及線程數的總體變化情況。頁面上還有兩個按鈕執行垃圾回收和堆dump,操作按鈕可以立即執行full gc(下圖堆大小減少)和生存堆快照。
線程分析
切換到線程tab可以看到應用中線程的資訊,展現了線程的數量,右上角有個線程Dump的按鈕,可以下載下傳目前所有現場的堆棧資訊(相當于jstack)。最下面還可以點選每個線程,展示每個線程的資訊,如果存在死鎖,會以紅色字型給出提示,如下圖
點選線程Dump按鈕,擷取的堆棧資訊,例如其中的死鎖資訊,可以直接看到發生死鎖的具體位置
性能分析
切換到抽樣器tab 可以看到共有CPU和記憶體兩個性能采樣器,可以實時的監控對應應用的CPU和記憶體變化。CPU采樣器可以将CPU占用時間定位到具體方法,而記憶體采樣器可以檢視目前應用的堆資訊,根據頁面CPU和記憶體的按鈕選擇。
CPU采樣
下面這個例子讓程式占用CPU,看看監控上是什麼樣子
public class Test2 {
public static void main(String[] args) throws InterruptedException {
fullCpu();
}
private static void fullCpu() throws InterruptedException {
long startTime = 0;
while (true) {
startTime = System.currentTimeMillis();
while (System.currentTimeMillis() - startTime < 8) {
}
Thread.sleep(2);
}
}
}
如下圖Test2.fullCpu()方法占用了大量的CPU時間,而其他方法就比較空閑。通過這個tab,我們可以很快速友善的定位到應用中最耗資源的方法并解決。(而線程CPU時間,可以看到是根據CPU資源消耗大小對線程的排序)
記憶體采樣
通過記憶體采樣可以實時檢視每個類記憶體占用情況,在應用運作的過程中,visual VM實時更新資料,動态的顯示各個class記憶體占用的大小,同時還可以檢視每個線程配置設定的記憶體大小。如下圖
GC資訊
切換到Visual GC的tab,可以看到堆的資訊變化的圖表,包括Metaspace,老年代,新生代的伊甸區,S0區和S1區的實時動态資料。
Btrace動态跟蹤
Btrace的作用是使在不停機的情況下,通過Hotspot虛拟機的Instrument功能動态的加入調試代碼。可以跟蹤指定的方法調用,構造函數以及系統記憶體等資訊,我感覺主要的意義在于如當程式出現問題時,排查錯誤的一些必要資訊時 (譬如方法參數、傳回值等),在開發時并沒有列印到日志之中以至于不得不停掉服務時,都可以通過調試增量來加入日志代碼以解決問題。
可以說Btrace是檢查和解決線上問題的大招,不用重新開機服務,通過腳本指令執行。
安裝Btrace插件之後在對應的應用右鍵選擇
Trace Application
就會進入對應的操作面闆,一個代碼輸入的控制頁面。
這個舉個例子:已經上線的代碼出現空指針,但是對應直接看不出具體原因,需要輸出一些額外資訊輔助判斷,或者需要在日志中輸出一些額外資訊。
線上代碼如下
public class Test2 {
public static int add(int a, int b) {
return a + b;
}
public static void main(String[] args) throws InterruptedException {
while (true){
int a = (int) Math.round(Math.random() * 100);
int b = (int) Math.round(Math.random() * 100);
add(a,b);
Thread.sleep(2000);
}
}
}
現在上面的代碼已經線上上運作了,但是我現在需要知道a,b兩個随機參數的具體值是什麼,可以打開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="/.*Test2", // 監控以Test2結尾的類
method="add",
location=@Location(Kind.RETURN))
public static void func(int a,int b, @Return int result){
println("開始===============");
jstack();
println(strcat("方法參數A:",str(a)));
println(strcat("方法參數B:",str(b)));
println(strcat("方法結果:",str(result)));
}
}
@OnMethod中參數的clazz需要控制的類,method是類中的方法,location中的Kind.RETURN是指方法結束後輸出資訊以及堆棧資訊。想深入了解這三種參數的具體使用方法請自行百度:“Btrace Java”
然後點選Start按鈕就會開始執行,看到控制台輸出的資訊,如圖
BTrace的用途很廣泛,列印調用堆棧、參數、傳回值隻是它最基礎的使用形式。還可以實作的功能包括
監控指定函數的耗時
,
擷取任意行代碼資訊
,
腳本定時
,
擷取類的屬性
等。
在官網上有使用BTrace進行性能監視、定位連接配接洩漏、記憶體洩漏、解決多線程競争問題等的使用案例,有興趣的讀者可以去網上了解相關資訊。
官網在此:github.com/btraceio/bt…
我是紀先生,用輸出倒逼輸入而持續學習,持續分享技術系列文章,以及全網值得收藏好文,歡迎關注公衆号,做一個持續成長的技術人。
個人網站
JVM虛拟機系列曆史文章
1. 虛拟機系列:jvm運作時堆記憶體如何分代;
2. 虛拟機系列:jvm中的垃圾回收算法;
3. 虛拟機系列:jvm運作時資料區域;
4. 虛拟機系列:JVM中對象的建立,記憶體布局和通路定位;
5. 虛拟機系列:JVM中的垃圾收集器;
6. 虛拟機系列:JVM中的記憶體配置設定;
7. 虛拟機系列:搞懂虛拟機的日志和日志參數;
8. 虛拟機系列:虛拟機性能監控基礎工具;