記得前幾天有人問我:在生產環境中可能常常遇到各類問題,大家通常是如何進行調試的? 很慚愧,沒有經驗。由於平時碰不到生產環境的服務器,定位問題須要各類數據,因此大多數問題的解決方式都是在本地打斷點進行調試,或者在測試環境利用輸出日誌進行調試,這種方式簡單粗暴,但過程比較繁瑣,須要各類從新發布,重啓應用,還不能保證一次就找到問題的根源。直到最近才瞭解到Btrace這個工具,對於這樣一個神器,我以爲有必要記錄一篇,讓更多的人知道。java
BTrace是sun公司推出的一款Java 動態、安全追蹤(監控)工具,能夠在不用重啓的狀況下監控系統運行狀況,方便的獲取程序運行時的數據信息,如方法參數、返回值、全局變量和堆棧信息等,而且作到最少的侵入,佔用最少的系統資源。git
項目地址:Btrace
用戶指南:UserGuidegithub
因爲Btrace會把腳本邏輯直接侵入到運行的代碼中,因此在使用上作不少限制:
一、不能建立對象
二、不能使用數組
三、不能拋出或捕獲異常
四、不能使用循環
五、不能使用synchronized關鍵字
六、屬性和方法必須使用static修飾正則表達式
根據官方聲明,不恰當的使用BTrace可能致使JVM崩潰,如在BTrace腳本使用錯誤的class文件,因此在上生產環境以前,務必在本地充分的驗證腳本的正確性。數組
一、接口性能變慢,分析每一個方法的耗時狀況;
二、當在Map中插入大量數據,分析其擴容狀況;
三、分析哪一個方法調用了System.gc(),調用棧如何;
四、執行某個方法拋出異常時,分析運行時參數;
五、....安全
package com.metty.rpc.common; import java.util.Random; /** * Created by j_zhan on 2016/11/28. */ public class BtraceCase { public static Random random = new Random(); public int size; public static void main(String[] args) throws Exception { new BtraceCase().run(); } public void run() throws Exception { while (true) { add(random.nextInt(10), random.nextInt(10)); } } public int add(int a, int b) throws Exception { Thread.sleep(random.nextInt(10) * 100); return a + b; } }
執行add方法時,對傳入參數、返回值以及執行耗時進行分析,btrace腳本:服務器
經過jps命令獲取pid爲8454
執行btrace 8454 Debug.java
實現對運行代碼的監控,輸出結果以下:dom
能夠發現,Btrace能夠獲取每次執行add方法時的數據,固然Btrace能作的遠遠不止這些,好比獲取當前jvm堆使用狀況、當前線程的執行棧等等。jvm
Btrace使用@OnMethod註解定義須要分析的方法入口ide
在@OnMethod註解中,須要指定class、method以及location等,class代表須要監控的類,method代表須要監控的方法,指定方式以下:
一、使用全限定名:clazz="com.metty.rpc.common.BtraceCase", method="add"
二、使用正則表達式:clazz="/javax\\.swing\\..*/", method="/.*/"
三、使用接口:clazz="+com.ctrip.demo.Filter", method="doFilter"
四、使用註解:clazz="@javax.jws.WebService", method=""@javax.jws.WebMethod"
五、若是須要分析構造方法,須要指定method="<init>"
定義Btrace對方法的攔截位置,經過@Location註解指定,默認爲Kind.ENTRY
一、Kind.ENTRY:在進入方法時,調用Btrace腳本
二、Kind.RETURN:方法執行完時,調用Btrace腳本,只有把攔截位置定義爲Kind.RETURN,才能獲取方法的返回結果@Return和執行時間@Duration
三、Kind.CALL:分析方法中調用其它方法的執行狀況,好比在execute方法中,想獲取add方法的執行耗時,必須把where設置成Where.AFTER
四、Kind.LINE:經過設置line,能夠監控代碼是否執行到指定的位置
五、Kind.ERROR, Kind.THROW, Kind.CATCH
用於對某些異常狀況的跟蹤,包括異常拋出,異常被捕獲,異常未捕獲被拋出方法以外
一、找出全部耗時超過1ms的過濾器Filter
因爲@Dutation返回的時間是納秒級別,須要進行轉換,若是定位一個Filter性能變慢,接着使用@Location(Kind.CALL)進行更細粒度的分析。
二、分析哪一個方法調用了System.gc(),調用棧如何?
經過查看調用棧,能夠很清楚的發現哪一個類哪一個方法調用了System.gc()
三、統計方法的調用次數,且每隔1分鐘打印調用次數
Btrace的@OnTimer註解能夠實現定時執行腳本中的一個方法
四、方法執行時,查看對象的實例屬性值
經過反射機制,能夠很方法的獲得當前實例的屬性值
Btrace能作的事情太多,但使用以前切記檢查腳本的可行性,一旦Btrace腳本侵入到系統中,只有經過重啓才能恢復。