下載下傳和安裝
curl -O https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar
使用as.sh
curl -L https://alibaba.github.io/arthas/install.sh | sh
直接在shell下面執行./as.sh,就會進入互動界面。
也可以執行./as.sh -h來擷取更多參數資訊。
常用的指令
基本指令
- help——檢視指令幫助資訊
- cat——列印檔案内容,和linux裡的cat指令類似
- pwd——傳回目前的工作目錄,和linux指令類似
- cls——清空目前螢幕區域
- session——檢視目前會話的資訊
- reset——重置增強類,将被 Arthas 增強過的類全部還原,Arthas 服務端關閉時會重置所有增強過的類
- version——輸出目前目标 Java 程序所加載的 Arthas 版本号
- history——列印指令曆史
- quit——退出目前 Arthas 用戶端,其他 Arthas 用戶端不受影響
- shutdown——關閉 Arthas 服務端,所有 Arthas 用戶端全部退出
檢視系統整體情況
- dashboard——目前系統的實時資料面闆
- thread——檢視目前 JVM 的線程堆棧資訊
- jvm——檢視目前 JVM 的資訊
- sysprop——檢視和修改JVM的系統屬性
- sysenv——檢視JVM的環境變量
- getstatic——檢視類的靜态屬性
類相關指令
- sc——檢視JVM已加載的類資訊
- sm——檢視已加載類的方法資訊
- jad——反編譯指定已加載類的源碼
- mc——記憶體編繹器,記憶體編繹.java檔案為.class檔案
- redefine——加載外部的檔案,redefine到JVM裡
- dump——dump 已加載類的 byte code 到特定目錄
- classloader——檢視classloader的繼承樹,urls,類加載資訊,使用classloader去getResource
監控相關
- monitor——方法執行監控
- watch——方法執行資料觀測
- trace——方法内部調用路徑,并輸出方法路徑上的每個節點上耗時
- stack——輸出目前方法被調用的調用路徑
- tt——方法執行資料的時空隧道,記錄下指定方法每次調用的入參和傳回資訊,并能對這些不同的時間下調用進行觀測
問題
- 初次使用時的一些問題
[ERROR] Target process 9298 is not the process using port 3658, you will connect to an unexpected process.
[ERROR] 1. Try to restart as.sh, select process 959, shutdown it first with running the 'stop' command.
[ERROR] 2. Try to use different telnet port, for example: as.sh --telnet-port 9998 --http-port -1
這個問題初用者必出,原因為 arthas 選擇一個應用進行診斷時弄了一個 session,可以使用 arthas-client ,web arthas client 進行登入,這個提示告訴你要先關閉以前的 arthas-boot ,或者重新選擇一個端口。
在 ~/.arthas/lib/3.1.7/arthas 下有一個 arthas-client.jar 使用 java -jar arthas-client.jar 可以進入上次的 session ,shutdown 後就可以選擇其它的程序進行診斷了,或者你可以繼續診斷目前應用
- 反編譯失敗
Memory compiler error, exception message: Compilation Error
line: 9 , message: package org.springframework.stereotype does not exist ,
line: 11 , message: cannot find symbol
symbol: class Service ,
, please check $HOME/logs/arthas/arthas.log for more details.
Affect(row-cnt:0) cost in 16 ms.
- mc指令有可能失敗。如果編譯失敗可以在本地編譯好.class檔案,再上傳到伺服器
- 可以使用sc命名查找相應類的ClassLoader,擷取classLoaderHash。再用mc指令進行反編譯
# 擷取classLoaderHash
sc -d *SayService | grep classLoaderHash
# classLoaderHash 439f5b3d
# 使用classLoaderHash進行反編譯
mc -c 439f5b3d /tmp/SayService.java -d /tmp
實戰操作
- 使用monitor指令對類、方法的調用進行監控。
monitor -c 2 com.example.arthastest.service.SayService sayHello

從上圖的監控可以看出類SayService的sayHello方法耗時抖動比較大,需進一步排查
- 使用trace指令對方法内部調用路徑,并輸出方法路徑上的每個節點上耗時統計
trace com.example.arthastest.service.SayService sayHello '#cost > 300'
從上圖的監控資料可以看到processName方法耗時多
- 使用watch指令觀察到指定方法的調用情況。能觀察到的範圍為:傳回值、抛出異常、入參,通過編寫 OGNL 表達式進行對應變量的檢視。
watch com.example.arthastest.service.SayService processName "{params,returnObj}" -x 2 '#cost>300'
從上圖的監控可以看出傳入參數xiaoming時的耗時較多
- 使用jad反編譯指定已加載類的源碼
jad --source-only com.example.arthastest.service.SayService
# 可以使用如下指令将生成後的源碼指定到檔案中
jad --source-only com.example.arthastest.service.SayService > /tmp/SayService.java
看到反編譯後的代碼,基本可以确認問題出在哪裡。
- 使用sc指令擷取加載該方法的classLoaderHash
sc -d *SayService | grep classLoaderHash
-
修改源碼後使用mc編譯.java檔案生成.class
修改後的源碼如下圖
mc -c 439f5b3d /tmp/SayService.java -d /tmp
- 使用redefine指令重新加載修改後的代碼
redefine -c 439f5b3d /tmp/com/example/arthastest/service/SayService.class
再次使用相同的參數通路該方法,會發現耗時明顯降低。
注意:redefine指令和jad/watch/trace/monitor/tt等指令會沖突。執行完redefine之後,如果再執行上面提到的指令,則會把redefine的位元組碼重置。 原因是jdk本身redefine和Retransform是不同的機制,同時使用兩種機制來更新位元組碼,隻有最後修改的會生效。redefine後使用jad再次檢視源碼會發現依舊是以前的,這是指令沖突導緻的,會使已生效redefine修改失效。