當咱們系統遇到JVM或者內存溢出等問題的時候,如何對咱們的程序進行有效的監控和排查,就發現了幾個比較經常使用的工具,好比JDK自帶的 jconsole、jvisualvm
還有一個最好用的工具——jprofiler
,可是這個是收費的,或者除了頗有錢的公司,通常不多人會用這個,還有一個就是咱們今天的主角——Arthas ,爲何今天會重點講這個呢?html
官網地址:arthas.gitee.io/ GitHub地址:github.com/alibaba/art…java
Arthas 是Alibaba開源的Java診斷工具,採用命令行交互模式,提供了較爲豐富的功能,主要仍是他是免費裏面的算是好用且功能比較強大的一個JVM排查的插件,在瞭解這個利器以後,發現仍是挺好用的,並且支持的功能也比較全面,那麼Arthas到底能夠爲咱們作哪些事情呢?git
之前,你碰到這些問題,解決的辦法大可能是,修改代碼,從新上線。可是在大公司裏,上線的流程是很是繁瑣的,若是爲了多加一行日誌而從新發布版本,無疑是很是折騰人的。可是阿里巴巴開源的Arthas 有了更爲優雅的線上調試方法。github
Arthas 支持JDK6,同時能夠在 Linux/Mac/Windows
上運行,自動Tab 補全功能,更方便咱們定位問題和診斷web
下載地址:arthas.gitee.io/download.ht… 你能夠下載zip的包我下載的是arthas-packaging-3.5.0-bin.zip 或者經過命令去下載正則表達式
wget https://alibaba.github.io/arthas/arthas-boot.jar
算法
當咱們下載好以後,咱們直接經過命令啓動就能夠java -jar arthas-boot.jar
,可是在此以前咱們須要經過檢測的代碼來掛靠到Arthas上面apache
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class FullGCTest {
//模擬銀行卡的類
private static class CardInfo {
//小農的銀行卡信息記錄
BigDecimal price = new BigDecimal(10000000.0);
String name = "牧小農";
int age = 18;
Date birthdate = new Date();
public void m() {}
}
//線程池 定時線程池
//50個,而後設置 拒絕策略
private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50,
new ThreadPoolExecutor.DiscardOldestPolicy());
public static void main(String[] args) throws Exception {
executor.setMaximumPoolSize(50);
for (;;){
modelFit();
Thread.sleep(100);
}
}
/** * 對銀行卡進行風險評估 */
private static void modelFit(){
List<CardInfo> taskList = getAllCardInfo();
//拿出每個信息出來
taskList.forEach(info -> {
// do something
executor.scheduleWithFixedDelay(() -> {
//調用M方法
info.m();
}, 2, 3, TimeUnit.SECONDS);
});
}
private static List<CardInfo> getAllCardInfo(){
List<CardInfo> taskList = new ArrayList<>();
//每次查詢100張卡出來
for (int i = 0; i < 100; i++) {
CardInfo ci = new CardInfo();
taskList.add(ci);
}
return taskList;
}
}
複製代碼
這個是上篇文章講述的案例,感興趣的能夠了解一下。centos
首先咱們須要使用javac 命令將Java文件進行編譯javac FullGCTest.java進行編譯,而後打印GC日誌,進行風險監控打印GC日誌: java -Xms200M -Xmx200M -XX:+PrintGC FullGCTest
服務器
Arthas啓動命令:java -jar arthas-boot.jar
咱們就看到了咱們剛纔啓動的FullGCTest的應用程序,咱們輸入編號 1 回車,這樣咱們就把Arthas掛靠到咱們的程序上,接下來咱們只須要作對應的命令操做就能夠了
命令詳情文檔:arthas.aliyun.com/doc/command…
命令 | 詳細說明 |
---|---|
jvm | 查看當前JVM信息 |
thread | 查看當前JVM的線程堆棧信息 |
watch | 方法執行數據觀測 |
dashboard | 當前系統的實時數據面板 |
trace | 方法內部調用路徑,並輸出方法路徑上的每一個節點上耗時 |
stack | 輸出當前方法被調用的調用路徑 |
tt | 方法執行數據的時空隧道,記錄下指定方法每次調用的入參和返回信息,並能對這些不一樣的時間下調用進行觀測 |
vmoption | 查看,更新JVM已加載的類信息 |
sc | 查看JVM已加載的類信息 |
sm | 查看已加載類的方法信息 |
jad | 反編譯指定已加載類的源碼 |
classloader | 查看classloader的繼承樹,urls,類加載信息 |
heapdump | 相似jmap命令的heap dump 功能 |
OPERATING-SYSTEM:系統相關參數
THREAD相關:
MEMORY
FILE-DESCRIPTOR(文件描述符相關):
參數說明:
命令 | 詳細說明 |
---|---|
id | 線程id |
[n:] | 指定最忙的前N個線程並打印堆棧 |
[b] | 找出當前阻塞其餘線程的線程 |
[i] | 指定cpu使用率統計的採樣間隔,單位爲毫秒,默認值爲200 |
[--all] | 顯示全部匹配的線程 |
打印當前最忙的N個線程並打印堆棧 thread -n 3
thread 查看全部線程
thread 17: 顯示指定線程的運行堆棧
thread -i: 指定採樣時間間隔
thread -i 1000 : 統計最近1000ms內的線程CPU時間。 thread -n 3 -i 1000 : 列出1000ms內最忙的3個線程棧
運行程序時,會顯示當前程序的實時信息,如qps, rt, 錯誤數, 線程池信息等等
數聽說明:
參數說明:
參數名稱 | 詳細說明 |
---|---|
id | 刷新實時數據的時間間隔 (ms),默認5000ms |
[n:] | 刷新實時數據的次數 |
查看JVM已加載的類信息,經過SC咱們能夠看到咱們這個類的詳細信息,包括是從哪一個jar包讀取的,他是否是接口/枚舉類等,甚至包括他是從哪一個類加載器加載的。
參數說明:
參數名稱 | 詳細說明 |
---|---|
class-pattern | 類名錶達式匹配 |
method-pattern | 方法名錶達式匹配 |
[d] | 輸出當前類的詳細信息,包括這個類所加載的原始文件來源、類的聲明、加載的ClassLoader等詳細信息。若是一個類被多個ClassLoader所加載,則會出現屢次 |
[E] | 開啓正則表達式匹配,默認爲通配符匹配 |
sc -d *CardInfo
: 打印類的詳細信息
sc -d -f *CardInfo
:打印類的Fiedld信息
heapdump:相似於jmap命令
建立到指定文件夾下:
[arthas@365564]$ heapdump /usr/local/mxn/dump.hprof
Dumping heap to /usr/local/mxn/dump.hprof ...
Heap dump file created
複製代碼
建立成功後,咱們就能夠在指定文件夾下看到對應的dump文件,而後使用命令jhat dump.hprof
,生成文件,成功後咱們就能夠經過IP+端口進行訪問了
訪問:
而後咱們就能夠經過IP+端口去訪問它了,裏面有個他的other,咱們拉到最底下,找 Show instance counts for all classes (including platform)
從下面咱們能夠分析出來哪一個類包含的對象最多,分析出來哪一個類產生的對象
這個裏面最強大的功能仍是叫作 Execute Object Query Language (OQL) query
,這個裏面能夠顯示有哪些對象,對象有多少個字節和引用,能夠觀察到哪一個對象產生了問題,以下圖所示,顯示全部String對應的對象
搜索點進去以後咱們還能看到這個對象到底佔用了多少個字節,有多少個引用指向了這個Object,這個OQL的語法也是很靈活,咱們可使用where條件去過濾
jad:反編譯某個類,或者反編譯某個類的某個方法,動態代理生成類的問題定位 第三方的類(觀察代碼) 版本問題(肯定本身最新提交的版本是否是被使用)
有人可能會問這個有啥用,源碼我不是本身就知道嗎?由於有時咱們常常會不肯定線上或者測試環境的包是不是咱們修改過的,這時候就能夠經過jad反編譯來看下,是不是最新的代碼
redafine:熱替換,動態更新代碼,不用重啓jvm目前有些限制條件:只能改方法實現(方法已經運行完成),不能改方法名, 不能改屬性 m() -> mm()
好比咱們在線上環境有個class確認有問題,想要從新替換,通常狀況下只能停掉服務器從新發布,在普通的小公司這樣是能夠的,可是在大規模公司京東淘寶這樣的是不能停的,由於整個流程是很是複雜的,那怎麼辦呢?你們能夠看到下面的案例
首先咱們新建一個測試案例:
public class T{
public static void main(String[] args) throws Exception{
for(;;){
System.in.read();
new TT().m();
}
}
}
複製代碼
public class TT{
public void m(){
System.out.println(2);
}
}
複製代碼
使用命令javac *.java
,編譯成class文件,而後運行 T 文件
[root@VM-0-7-centos t]# java T
a
2
2
複製代碼
當咱們輸入a的時候打印2,可是咱們上線之後才發現,咱們須要輸出的1,這個是若是要從本地更改要從新發布上線,爲了這一個修改,明顯是不值當的,可是若是咱們用 redafine 熱部署就能夠幫助咱們直接替換,不用從新發布jvm
而後咱們將 T 這個程序掛靠到 Arthas 上面去
而後咱們直接修改 TT.java 程序 vi TT.java
,將裏面打印2的值修改爲1
public class TT{
public void m(){
System.out.println(1);
}
}
複製代碼
而後編譯執行 ```javac TT.java ````
在回到咱們掛靠的Arthas 上面執行 redefine /usr/local/mxn/fuccGc/t/TT.class
[arthas@398842]$ redefine /usr/local/mxn/fuccGc/t/TT.class
redefine success, size: 1, classes:
TT
複製代碼
執行成功 你們能夠看到咱們在沒有從新啓動的狀況下成功替換了class文件
watch:方法執行的數據觀測,能夠經過watch指令,來監控某個類,監控後,運行下你的功能,復現下場景,arthas會提供給你具體的出參和入參,幫助你排查故障
輸出方法調用路徑,並輸出耗時,這個指令對於優化代碼很是的有用,能夠看出具體每一個方法執行的時間,若是是for循環等重複語句,還能看出n次循環中的最大耗時,最小耗時,和平均耗時,完美!
在咱們對某個方法開啓tt後,會記錄每一次調用(咱們能夠設置最大監控次數)的入參和返回參數,並能對這些不一樣時間下調進行觀測
[arthas@405136]$ tt -t FullGCTest modelFit
命令參數解析-t tt 命令有不少個主參數,-t 就是其中之一。這個參數的代表但願記錄下類 *Test 的 print 方法的每次執行狀況。 -n 3 當你執行一個調用量不高的方法時可能你還能有足夠的時間用 CTRL+C 中斷 tt 命令記錄的過程,但若是遇到調用量很是大的方法,瞬間就能將你的 JVM 內存撐爆。
此時你能夠經過 -n 參數指定你須要記錄的次數,當達到記錄次數時 Arthas 會主動中斷tt命令的記錄過程,避免人工操做沒法中止的狀況。
ognl表達式
OGNL特殊用法請參考:github.com/alibaba/art… OGNL表達式官方指南:commons.apache.org/proper/comm…
調用靜態函數:ognl '@java.lang.System@out.println("hello")'
獲取靜態類的靜態字段:ognl '@FullGCTest@random'
Arthas還支持Web Console,詳見:alibaba.github.io/arthas/web-…
Arthas是一個線上Debug神器,相比於其餘工具,Arthas有着比較全面的功能,上手也比較容易,對於剛開始入門的小夥伴也是能夠輕鬆掌握的,對於文中有不懂或者有問題的小夥伴,你們能夠在下面留言評論。
原創不易,但願你們多多捧場,記得一鍵三連!!!
我是牧小農,怕什麼真理無窮,進一步有進一步的歡喜,你們加油!