Arthas 使用(一) —— 基礎命令




Arthas 簡介

Arthas 是 Alibaba 開源的 Java 診斷工具,根據官方介紹,它提供了如下工功能:

image-20200517111854420

官方文檔地址: https://alibaba.github.io/arthas/

github 源碼地址: https://github.com/alibaba/arthas


Arthas 安裝

啟動 Arthas

# 下載 arthas
curl -O https://alibaba.github.io/arthas/arthas-boot.jar
# 通過如下命令啟動
java -jar arthas-boot.jar

image-20200517155128106

選擇進程 id 按下回車,就可以連接到對應的 java 應用,首次啟動會下載一些文件到 "C:/Users/${user}/.arthas/lib/3.2.0/arthas" 目錄

20200517154635722

arthas 啟動支持多個參數,可以使用 -h 查看

image-20200517161835635

EXAMPLES:
  java -jar arthas-boot.jar <pid>
  java -jar arthas-boot.jar --target-ip 0.0.0.0
  java -jar arthas-boot.jar --telnet-port 9999 --http-port -1
  java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws'
  java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws'
--agent-id bvDOe8XbTM2pQWjF4cfw
  java -jar arthas-boot.jar --stat-url 'http://192.168.10.11:8080/api/stat'
  java -jar arthas-boot.jar -c 'sysprop; thread' <pid>
  java -jar arthas-boot.jar -f batch.as <pid>
  java -jar arthas-boot.jar --use-version 3.2.0
  java -jar arthas-boot.jar --versions
  java -jar arthas-boot.jar --session-timeout 3600
  java -jar arthas-boot.jar --attach-only
  java -jar arthas-boot.jar --repo-mirror aliyun --use-http
WIKI:
  https://alibaba.github.io/arthas

help

arthas 連接成功后,使用 help 可以看到提供的一些命令

image-20200517155940521

每個命令可以使用 -h 參數查看幫助信息,里面有EXAMPLESWIKI鏈接

image-20200517154635722


webconsole

arthas 啟動后,可以通過瀏覽器進行訪問,地址 http://localhost:8563/

image-20200517162105397


退出

如果只是退出當前的連接,可以用quit或者exit命令。Attach到目標進程上的arthas還會繼續運行,端口會保持開放,下次連接時可以直接連接上。

如果想完全退出arthas,可以執行stop命令。


Arthas 命令

dashboard

查看面板信息,主要包含cpu 內存使用信息,可以按 Ctrl+C 或者 輸入 q 退出

_images/dashboard.png

數據說明

  • ID: Java級別的線程ID,注意這個ID不能跟jstack中的nativeID一一對應
  • NAME: 線程名
  • GROUP: 線程組名
  • PRIORITY: 線程優先級, 1~10之間的數字,越大表示優先級越高
  • STATE: 線程的狀態
  • CPU%: 線程消耗的cpu占比,采樣100ms,將所有線程在這100ms內的cpu使用量求和,再算出每個線程的cpu使用占比。
  • TIME: 線程運行總時間,數據格式為分:秒
  • INTERRUPTED: 線程當前的中斷位狀態
  • DAEMON: 是否是daemon線程

thread

查看線程使用情況

# 查看所有線程信息
thread
# 查看具體線程的棧,查看線程ID 16的棧:
thread 16
# 查看CPU使用率top n線程的棧
thread -n 3
# 查看5秒內的CPU使用率top n線程棧
thread -n 3 -i 5000
# 查找線程是否有阻塞
thread -b

image-20200517163025955


sysprop

查看當前JVM的系統屬性,支持 pipeline

sysprop # 查詢所有屬性
sysprop key # 查看key對應的屬性
sysprop key value # 修改屬性值
sysprop | grep java # 查詢包含java的屬性
sysprop | wc -l # 統計數量

image-20200517163647024


sysenv

查看當前JVM的環境屬性

用法和 sysprop 類似,不支持修改

image-20200517170505831


logger

查看logger信息,更新logger level

logger # 查看所有logger對象信息
logger -n [name] # 查看名為name的logger信息
logger -c [classloader] -n [name] -l ERROR # 修改名為name的logger級別為ERROR,需指定類加載器

image-20200517165827604


sc

查看JVM已加載的類信息

sc -d org.apache.commons.lang.StringUtils # 查看StringUtils詳細信息
sc -d org/apache/commons/lang/StringUtils # 查看StringUtils詳細信息
sc -d *StringUtils # 查看StringUtils,根據*匹配
sc -d -f org.apache.commons.lang.StringUtils # 查看類及成員變量信息,f要配合d使用才有效

image-20200517165504773


sm

查看已加載類的方法信息,用法和 sc 類似

sm java.lang.String # 查看String的所有方法
sm -d org.apache.commons.lang.StringUtils # 查看String方法詳情
sm -d org/apache/commons/lang/StringUtils # 查看String方法詳情
sm *StringUtils *  # 查看String方法,根據*匹配

image-20200517170620766


dump

dump 已加載類的 bytecode 到特定目錄

dump java.lang.String # dump java.lang.String.class文件
dump java.lang.* # dump 批量dump
dump -d /tmp/output java.lang.String # dump到指定目錄
dump org/apache/commons/lang/StringUtils # dump,支持目錄格式
dump *StringUtils # dump,根據*匹配

image-20200517164153476


jad

反編譯指定已加載類的源碼

jad java.lang.String # 反編譯String類
jad java.lang.String toString # 反編譯指定方法
jad --source-only java.lang.String # 反編繹時只顯示源代碼
jad -c 39eb305e org/apache/log4j/Logger # 反編譯指定classloader

image-20200517171304855


classloader

查看classloader的繼承樹,urls,類加載信息

classloader	# 列出所有classLoader
classloader -t # 樹形結構列出所有classLoader
classloader -l # 統計每個classLoader加載類數量
classloader -c 327a647b # 查看具體的classLoader
classloader -a # 列出所有加載的類
classloader -c 659e0bfd --load demo.MathGame # 使用指定classLoader加載類

image-20200517171909021


mc

編譯.java文件生成.class

mc /tmp/Test.java	# 編譯Test.java
mc -c 327a647b /tmp/Test.java # 使用 -c 指定classLoader
mc -d /tmp/output /tmp/ClassA.java /tmp/ClassB.java # 使用 -d 指定輸出目錄

redefine

加載外部的.class文件

redefine命令和jad/watch/trace/monitor/tt等命令會沖突。執行完redefine之后,如果再執行上面提到的命令,則會把redefine的字節碼重置。 原因是jdk本身redefine和Retransform是不同的機制,同時使用兩種機制來更新字節碼,只有最后修改的會生效。

redefine /tmp/Test.class	# 加載類
redefine -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class # 指定classLoader

通常結合 jad/mc 使用

  • jad命令反編譯,然后可以用其它編譯器,比如vim來修改源碼
  • mc命令來內存編譯修改過的代碼
  • 用redefine命令加載新的字節碼

redefine的限制

  • 不允許新增加 field/method
  • 正在跑的函數,沒有退出不能生效

watch

方法執行數據觀測

# 方法調用前觀察,可以是非靜態方法
watch -b org.apache.commons.lang.StringUtils isBlank params
# 在方法結束之后(正常返回和異常返回)觀察
watch -f org.apache.commons.lang.StringUtils isBlank returnObj
# 指定輸出結果的屬性遍歷深度,2
watch org.apache.commons.lang.StringUtils isBlank '{params, target, returnObj}' -x 2
# 耗時100ms時輸出
watch *StringUtils isBlank params '#cost>100'
@RestController
public class UserController {
    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Integer id) {
        if (null == id) {
            throw new IllegalArgumentException("id can not be null");
        }
        if (id < 1) {
            throw new IllegalArgumentException("id must be greater than 1");
        }
        return new User(id, "zhangsan");
    }
}

使用如下 watch 命令,然后訪問 http://localhost:9090/user/10

watch com.soulballad.usage.arthasdemo.web.UserController getUser "{params,target,returnObj}" -x 2 -b -s -n 2

image-20200517175917004

  • 參數里-n 2,表示只執行兩次
  • 輸出結果中,第一次輸出的是方法調用前的觀察結果,第二次輸出的是方法返回后的表達式的結果
  • 結果的輸出順序和事件發生的先后順序一致,和命令中 -s -b 的順序無關

trace

方法內部調用路徑,並輸出方法路徑上的每個節點上耗時

trace org.apache.commons.lang.StringUtils isBlank # 查看isBlank方法調用路徑及耗時
trace *StringUtils isBlank # 使用*匹配
trace *StringUtils isBlank '#cost>100' # 過濾只輸出耗時大於100ms的記錄
# 正則表達式,支持多個路徑記錄
trace -E com.test.ClassA|org.test.ClassB method1|method2|method3 
trace demo.MathGame run -n 5 # 只執行5次
trace demo.MathGame run --skipJDKMethod false # 不跳過jdk中方法,默認為true

image-20200517180614199


stack

輸出當前方法被調用的調用路徑

image-20200517181157825

支持條件過濾和 ognl 表達式


tt

方法執行數據的時空隧道,記錄下指定方法每次調用的入參和返回信息,並能對這些不同的時間下調用進行觀測

tt -t *StringUtils isEmpty # 記錄isEmpty方法調用
tt -t *StringUtils isEmpty params[0].length==1 # 解決方法重載
tt -l # 查看所有記錄
tt -i 1000 # 查詢index為1000的記錄詳情
tt -i 1000 -p # 根據index重新觸發調用
tt -i 1000 -p --replay-times 3 --replay-interval 3000 # 指定觸發間隔和次數
tt --delete-all # 刪除所有記錄

image-20200517190220743


ognl

執行ognl表達式

ognl '@java.lang.System@out.println("hello")' # 調用靜態函數
ognl -x 2 '@Singleton@getInstance()' # 2層
ognl '@Demo@staticFiled' # 輸出靜態變量值
# 把java.home和java.runtime.name的系統屬性放到一個集合中輸出
ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"), {#value1, #value2}'
ognl -c 5d113a51 '@com.taobao.arthas.core.GlobalOptions@isDump' # 輸出false


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM