溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何用Arthas排查JVM內(nèi)存

發(fā)布時間:2021-10-11 10:01:56 來源:億速云 閱讀:212 作者:iii 欄目:編程語言

本篇內(nèi)容主要講解“如何用Arthas排查JVM內(nèi)存”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“如何用Arthas排查JVM內(nèi)存”吧!

如何用Arthas排查JVM內(nèi)存

Arthas是啥

當(dāng)我們系統(tǒng)遇到JVM或者內(nèi)存溢出等問題的時候,如何對我們的程序進(jìn)行有效的監(jiān)控和排查,就發(fā)現(xiàn)了幾個比較常用的工具,比如JDK自帶的 jconsole、jvisualvm還有一個最好用的工具——jprofiler,但是這個是收費的,或者除了很有錢的公司,一般很少人會用這個,還有一個就是我們今天的主角——Arthas ,為什么今天會重點講這個呢?

官網(wǎng)地址:http://arthas.gitee.io/ GitHub地址:https://github.com/alibaba/arthas/

Arthas 是Alibaba開源的Java診斷工具,采用命令行交互模式,提供了較為豐富的功能,主要還是他是免費里面的算是好用且功能比較強(qiáng)大的一個JVM排查的插件,在了解這個利器之后,發(fā)現(xiàn)還是挺好用的,而且支持的功能也比較全面,那么Arthas到底可以為我們做哪些事情呢?

  1. 提供性能看板,包括線程、cpu、內(nèi)存等信息,并且會定時的刷新。

  2. 根據(jù)各種條件查看線程快照。找出cpu占用率最高的n個線程

  3. 輸出jvm的各種信息,如gc算法、jdk版本、ClassPath等

  4. 遇到問題無法在線上 debug,熱部署加日志直接替換

  5. 查看某個類的靜態(tài)屬性,也可以通過ognl語法執(zhí)行一些語句

  6. 查看已加載的類的詳細(xì)信息,這個類從哪個jar包加載的,查看類的方法的信息

  7. dump 類的字節(jié)碼到指定目錄

  8. 直接反編譯指定的類

  9. 快速定位應(yīng)用的熱點,生成火焰圖

  10. 可以監(jiān)控到JVM的實時運行狀態(tài)

以前,你碰到這些問題,解決的辦法大多是,修改代碼,重新上線。但是在大公司里,上線的流程是非常繁瑣的,如果為了多加一行日志而重新發(fā)布版本,無疑是非常折騰人的。但是阿里巴巴開源的Arthas 有了更為優(yōu)雅的線上調(diào)試方法。

Arthas 支持JDK6,同時可以在 Linux/Mac/Windows上運行,自動Tab 補(bǔ)全功能,更方便我們定位問題和診斷

下載地址:https://arthas.gitee.io/download.html 你可以下載zip的包我下載的是arthas-packaging-3.5.0-bin.zip 或者通過命令去下載

wget https://alibaba.github.io/arthas/arthas-boot.jar

使用手冊

1. 快速啟動

當(dāng)我們下載好之后,我們直接通過命令啟動就可以java -jar arthas-boot.jar,但是在此之前我們需要通過檢測的代碼來掛靠到Arthas上面

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 {
        //小農(nóng)的銀行卡信息記錄
        BigDecimal price = new BigDecimal(10000000.0);
        String name = "牧小農(nóng)";
        int age = 18;
        Date birthdate = new Date();

        public void m() {}
    }

    //線程池 定時線程池
    //50個,然后設(shè)置 拒絕策略
    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);
        }
    }

    /**
     * 對銀行卡進(jìn)行風(fēng)險評估
     */
    private static void modelFit(){
        List<CardInfo> taskList = getAllCardInfo();
        //拿出每一個信息出來
        taskList.forEach(info -> {
            // do something
            executor.scheduleWithFixedDelay(() -> {
                //調(diào)用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;
    }
}

這個是上篇文章講述的案例,感興趣的可以了解一下。

首先我們需要使用javac 命令將Java文件進(jìn)行編譯javac FullGCTest.java進(jìn)行編譯,然后打印GC日志,進(jìn)行風(fēng)險監(jiān)控打印GC日志: java -Xms200M -Xmx200M -XX:+PrintGC FullGCTest

Arthas啟動命令:java -jar arthas-boot.jar

如何用Arthas排查JVM內(nèi)存

我們就看到了我們剛才啟動的FullGCTest的應(yīng)用程序,我們輸入編號 1 回車,這樣我們就把Arthas掛靠到我們的程序上,接下來我們只需要做對應(yīng)的命令操作就可以了 如何用Arthas排查JVM內(nèi)存

命令詳情文檔:https://arthas.aliyun.com/doc/commands.html

2. 功能列表

命令詳細(xì)說明
jvm查看當(dāng)前JVM信息
thread查看當(dāng)前JVM的線程堆棧信息
watch方法執(zhí)行數(shù)據(jù)觀測
dashboard當(dāng)前系統(tǒng)的實時數(shù)據(jù)面板
trace方法內(nèi)部調(diào)用路徑,并輸出方法路徑上的每個節(jié)點上耗時
stack輸出當(dāng)前方法被調(diào)用的調(diào)用路徑
tt方法執(zhí)行數(shù)據(jù)的時空隧道,記錄下指定方法每次調(diào)用的入?yún)⒑头祷匦畔ⅲ⒛軐@些不同的時間下調(diào)用進(jìn)行觀測
vmoption查看,更新JVM已加載的類信息
sc查看JVM已加載的類信息
sm查看已加載類的方法信息
jad反編譯指定已加載類的源碼
classloader查看classloader的繼承樹,urls,類加載信息
heapdump類似jmap命令的heap dump 功能
jvm

如何用Arthas排查JVM內(nèi)存

OPERATING-SYSTEM:系統(tǒng)相關(guān)參數(shù)

THREAD相關(guān):

  • COUNT : JVM當(dāng)前活躍的線程數(shù)

  • DAEMON-COUNT : JVM當(dāng)前活躍的守護(hù)線程數(shù)

  • PEAK-COUNT: 從JVM啟動開始曾經(jīng)活著的最大線程數(shù)

  • STARTED-COUNT: 從JVM啟動開始總共啟動過的線程次數(shù)

  • DEADLOCK-COUNT: JVM當(dāng)前死鎖的線程數(shù)

MEMORY

FILE-DESCRIPTOR(文件描述符相關(guān)):

  • MAX-FILE-DESCRIPTOR-COUNT:JVM進(jìn)程最大可以打開的文件描述符數(shù)

  • OPEN-FILE-DESCRIPTOR-COUNT:JVM當(dāng)前打開的文件描述符數(shù)

thread 命令

參數(shù)說明:

命令詳細(xì)說明
id線程id
[n:]指定最忙的前N個線程并打印堆棧
[b]找出當(dāng)前阻塞其他線程的線程
[i]指定cpu使用率統(tǒng)計的采樣間隔,單位為毫秒,默認(rèn)值為200
[--all]顯示所有匹配的線程

打印當(dāng)前最忙的N個線程并打印堆棧 thread -n 3

如何用Arthas排查JVM內(nèi)存

thread 查看所有線程 如何用Arthas排查JVM內(nèi)存

thread 17: 顯示指定線程的運行堆棧 如何用Arthas排查JVM內(nèi)存

thread -i: 指定采樣時間間隔

thread -i 1000 : 統(tǒng)計最近1000ms內(nèi)的線程CPU時間。 thread -n 3 -i 1000 : 列出1000ms內(nèi)最忙的3個線程棧

dashboard 命令

運行程序時,會顯示當(dāng)前程序的實時信息,如qps, rt, 錯誤數(shù), 線程池信息等等

如何用Arthas排查JVM內(nèi)存

數(shù)據(jù)說明:

  • ID: Java級別的線程ID

  • NAME: 線程名

  • GROUP: 線程組名

  • PRIORITY: 線程優(yōu)先級, 1~10之間的數(shù)字,越大表示優(yōu)先級越高

  • STATE: 線程的狀態(tài)CPU%: 線程的cpu使用率。比如采樣間隔1000ms,某個線程的增量cpu時間為100ms,則cpu使用率=100/1000=10%

  • DELTA_TIME: 上次采樣之后線程運行增量CPU時間,數(shù)據(jù)格式為秒

  • TIME: 線程運行總CPU時間,數(shù)據(jù)格式為分:秒

  • INTERRUPTED: 線程當(dāng)前的中斷位狀態(tài)

  • DAEMON: 是否是daemon線程

如何用Arthas排查JVM內(nèi)存

參數(shù)說明:

參數(shù)名稱詳細(xì)說明
id刷新實時數(shù)據(jù)的時間間隔 (ms),默認(rèn)5000ms
[n:]刷新實時數(shù)據(jù)的次數(shù)
sc 命令

查看JVM已加載的類信息,通過SC我們可以看到我們這個類的詳細(xì)信息,包括是從哪個jar包讀取的,他是不是接口/枚舉類等,甚至包括他是從哪個類加載器加載的。

參數(shù)說明:

參數(shù)名稱詳細(xì)說明
class-pattern類名表達(dá)式匹配
method-pattern方法名表達(dá)式匹配
[d]輸出當(dāng)前類的詳細(xì)信息,包括這個類所加載的原始文件來源、類的聲明、加載的ClassLoader等詳細(xì)信息。如果一個類被多個ClassLoader所加載,則會出現(xiàn)多次
[E]開啟正則表達(dá)式匹配,默認(rèn)為通配符匹配

sc -d *CardInfo: 打印類的詳細(xì)信息 如何用Arthas排查JVM內(nèi)存

sc -d -f *CardInfo:打印類的Fiedld信息

如何用Arthas排查JVM內(nèi)存

heapdump + jhat分析

heapdump:類似于jmap命令

創(chuàng)建到指定文件夾下:

[arthas@365564]$ heapdump /usr/local/mxn/dump.hprof
Dumping heap to /usr/local/mxn/dump.hprof ...
Heap dump file created

創(chuàng)建成功后,我們就可以在指定文件夾下看到對應(yīng)的dump文件,然后使用命令jhat dump.hprof,生成文件,成功后我們就可以通過IP+端口進(jìn)行訪問了 如何用Arthas排查JVM內(nèi)存

訪問: 如何用Arthas排查JVM內(nèi)存

然后我們就可以通過IP+端口去訪問它了,里面有個他的other,我們拉到最底下,找 Show instance counts for all classes (including platform) 如何用Arthas排查JVM內(nèi)存

從下面我們可以分析出來哪個類包含的對象最多,分析出來哪個類產(chǎn)生的對象

如何用Arthas排查JVM內(nèi)存

這個里面最強(qiáng)大的功能還是叫做 Execute Object Query Language (OQL) query,這個里面可以顯示有哪些對象,對象有多少個字節(jié)和引用,可以觀察到哪個對象產(chǎn)生了問題,如下圖所示,顯示所有String對應(yīng)的對象 如何用Arthas排查JVM內(nèi)存 如何用Arthas排查JVM內(nèi)存

搜索點進(jìn)去之后我們還能看到這個對象到底占用了多少個字節(jié),有多少個引用指向了這個Object,這個OQL的語法也是很靈活,我們可以使用where條件去過濾

如何用Arthas排查JVM內(nèi)存

jad

jad:反編譯某個類,或者反編譯某個類的某個方法,動態(tài)代理生成類的問題定位 第三方的類(觀察代碼) 版本問題(確定自己最新提交的版本是不是被使用)

如何用Arthas排查JVM內(nèi)存

有人可能會問這個有啥用,源碼我不是自己就知道嗎?因為有時我們經(jīng)常會不確定線上或者測試環(huán)境的包是否是我們修改過的,這時候就可以通過jad反編譯來看下,是否是最新的代碼

redafine

redafine:熱替換,動態(tài)更新代碼,不用重啟jvm目前有些限制條件:只能改方法實現(xiàn)(方法已經(jīng)運行完成),不能改方法名, 不能改屬性 m() -> mm()

比如我們在線上環(huán)境有個class確認(rèn)有問題,想要重新替換,一般情況下只能停掉服務(wù)器重新發(fā)布,在普通的小公司這樣是可以的,但是在大規(guī)模公司京東淘寶這樣的是不能停的,因為整個流程是非常復(fù)雜的,那怎么辦呢?大家可以看到下面的案例

首先我們新建一個測試案例:

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

當(dāng)我們輸入a的時候打印2,但是我們上線以后才發(fā)現(xiàn),我們需要輸出的1,這個是如果要從本地更改要重新發(fā)布上線,為了這一個修改,明顯是不值當(dāng)?shù)?,但是如果我們?redafine 熱部署就可以幫助我們直接替換,不用重新發(fā)布jvm

然后我們將 T 這個程序掛靠到 Arthas 上面去 如何用Arthas排查JVM內(nèi)存

然后我們直接修改 TT.java 程序 vi TT.java,將里面打印2的值修改成1

public class TT{
        public void m(){
            System.out.println(1);
        }
}

然后編譯執(zhí)行 ```javac TT.java ````

在回到我們掛靠的Arthas 上面執(zhí)行 redefine /usr/local/mxn/fuccGc/t/TT.class

[arthas@398842]$ redefine /usr/local/mxn/fuccGc/t/TT.class
redefine success, size: 1, classes:
TT

執(zhí)行成功 大家可以看到我們在沒有重新啟動的情況下成功替換了class文件 如何用Arthas排查JVM內(nèi)存

watch

watch:方法執(zhí)行的數(shù)據(jù)觀測,可以通過watch指令,來監(jiān)控某個類,監(jiān)控后,運行下你的功能,復(fù)現(xiàn)下場景,arthas會提供給你具體的出參和入?yún)?,幫助你排查故?/p>

trace

輸出方法調(diào)用路徑,并輸出耗時,這個指令對于優(yōu)化代碼非常的有用,可以看出具體每個方法執(zhí)行的時間,如果是for循環(huán)等重復(fù)語句,還能看出n次循環(huán)中的最大耗時,最小耗時,和平均耗時,完美!

tt

在我們對某個方法開啟tt后,會記錄每一次調(diào)用(我們可以設(shè)置最大監(jiān)控次數(shù))的入?yún)⒑头祷貐?shù),并能對這些不同時間下調(diào)進(jìn)行觀測

[arthas@405136]$ tt -t FullGCTest modelFit

如何用Arthas排查JVM內(nèi)存

命令參數(shù)解析-t tt 命令有很多個主參數(shù),-t 就是其中之一。這個參數(shù)的表明希望記錄下類 *Test 的 print 方法的每次執(zhí)行情況。 -n 3 當(dāng)你執(zhí)行一個調(diào)用量不高的方法時可能你還能有足夠的時間用 CTRL+C 中斷 tt 命令記錄的過程,但如果遇到調(diào)用量非常大的方法,瞬間就能將你的 JVM 內(nèi)存撐爆。

此時你可以通過 -n 參數(shù)指定你需要記錄的次數(shù),當(dāng)達(dá)到記錄次數(shù)時 Arthas 會主動中斷tt命令的記錄過程,避免人工操作無法停止的情況。

到此,相信大家對“如何用Arthas排查JVM內(nèi)存”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI