JDK命令行工具與可視化工具

工具介紹

jdk/bin目錄中提供了不少jdk工具,在查看JVM運行狀態以及排查問題時須要結合Linux命令並結合這些工具進行使用,在此記錄經常使用命令行工具以及可視化工具的使用。 java

命令行工具

jps:虛擬機進程狀態工具

jps:主要用它定位Java進程的PID,示例代碼以下linux

/** jps -q:顯示進程ID -m:顯示進程ID,主類名稱,以及傳入main方法的參數 -1:顯示進程ID,主類全名 -v:顯示進程ID,王類名稱,以及傳入JWM的參數 -V:顯示進程ID,主類名稱(默認) */
public class DEMO01 {
    public static void main(String[] args) throws IOException {
        System.out.println("jps");
        //阻塞
        System.in.read();
    }
}
複製代碼

jstat:虛擬機信息監控工具

jstat:Linux環境上,運行期定位JVM性能問題的首選工具,經常使用來查看內存變化趨勢,GC狀況、類加載狀況等dom

使用格式 :jstat [option vmid [interval [s|ms] [count]] ]ide

  • option 表明咱們所要查詢的虛擬機細信息。主要包括:類裝載,垃圾回收,運行期編譯狀況 工具

  • vmid 如果運行在本地的虛擬機進程那就是程序運行的pid,如果遠程虛擬機,格式應該是 [protocol:][//]lvmid[@hostname[:port]/servername]post

  • interval 查詢間隔性能

  • count 查詢次數spa

忽略interval和count參數,那麼命令只會執行一次 好比 jstat -gc 2101 500 5 表示每500ms查詢一次2101進程的垃圾回收狀況,一共執行5次命令行

示例一:線程

public class DEMO02 {
    public static void main(String[] args) throws IOException {
        System.out.println("jstat");
        System.in.read();
    }
}
複製代碼

S0C,S1C是指Survivor0區1區的容量;S0U,S1U是指這兩倖存區的使用量;C表明Capacity,U表明Used,上面反應的是各個區的初始容量以及使用狀況,GC的次數和時間。

示例二:

import java.io.IOException;

public class DEMO03 {
    //啓動參數設置:-Xms20M -Xmx20M -Xmn10M -xx:+UseserialGC -XX: +PrintGcDetails -verbose:gc
    public static void main(String[] args) throws IOException {
        final int _1MB = 1024 * 1024;
        byte[] b1 = new byte[_1MB];
        System.out.println("1...");
        System.in.read();

        byte[] b2 = new byte[2*_1MB];
        System.out.println("2...");
        System.in.read();

        byte[] b3 = new byte[2*_1MB];
        System.out.println("3...");
        System.in.read();

    }
}

複製代碼

指定DEMO03運行時JVM參數,設置堆區爲20M,新生代10M,使用Serial垃圾收集器

能夠看到在三次打印中,Eden區發生的變化,發生了一次YoungGC,GC時間是0.015S

jstack:查看Java線程堆棧信息

使用格式:jstack [option] vmid

示例一:一段死循環ava程序,模擬linux環境下瘋狂佔用cpu資源

improt java.util.Random;
public class demo {

    public static void main(String[] args) {
        while(true){
            System.out.println(new Random().nextInt(77778888));
        }
    }
}
複製代碼

查看系統情況:用top命令去查各個進程CPU、內存的資源消耗狀況,找出最耗資源的進程pid,如圖所示,最耗資源的是java進程,pid是2818【須要在後臺運行很長時間纔會有反應.....】

定位到問題線程:定位到具體的問題線程ps -mp pid -o THREAD,tid,time 如圖所示在java進程中2819的線程最耗資源

查看問題線程的堆棧信息:先將線程id轉換爲16進制(英文小寫格式)printf "%x\n" 問題線程的id轉爲16進制英文小寫

在使用jstack查看線程的堆棧信息jstack pid |grep tid -A60

由此即可以查看到是demo.java中的第六行出了問題【此處只是小demo去模擬程序死循環,CPU線上預警出現的可能性不少,常見的還有內存泄露、死鎖、頻繁GC...須要結合linux命令和java命令和實際狀況進行逐步排查】

jinfo:查看/設置虛擬機的參數

jinfo能夠查看JVM的參數,並容許在程序運行期間修改JVM的參數,這樣JVM就不用重啓了。

使用格式:jinfo [option] pid,能夠經過-flag[+|-] name 添加和刪除一些參數,或者-flag name =value修改一些參數,可是不少參數是不容許修改的

public class DEMO04 {
    public static void main(String[] args) throws IOException {
        System.out.println("jinfo");
        System.in.read();
    }
}
複製代碼

jmap:生成dump文件

jmap用於生成一份堆存儲快照(dump),把Java堆區的使用狀況快照一份導出來供咱們排查問題。

使用格式 :jmap [option] vmid

示例:

public class DEMO05 {
    public static void main(String[] args) throws IOException {
        System.out.println("jmap");
        System.in.read();
    }
}
複製代碼

顯示堆區的詳細信息 jmap -heap pid

生成堆快照存儲文件,format=b生成的是二進制文件,jmap -dump:live,format=b,file=D:\jmap.bin pid

jhat:虛擬機存儲快照分析工具

使用jmap將堆區的快照文件導出後,可使用jhat進行分析,不過jhat如今使用較少。

使用格式: jhat [-stack ] [-refs ] [-port ] [-baseline ] [-debug ] [-version] [-h|-help]

示例:

可視化工具

jconcle

做用:查看Java應用程序運行時狀況,監視垃圾收集器的內存變化趨勢,以及監視程序內的線程。

示例一:JConsole演示內存變化

public class DEMO07 {
    public static void main(String[] args) throws IOException, InterruptedException {
        Thread.sleep(5000);
        System.out.println("start....");
        test();

        System.in.read();
    }

    public static void test() throws InterruptedException {
        final int _128K = 128 * 1024;
        List<byte[]> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            //耗時操做,令監視器的曲線變化更加明顯
            Thread.sleep(100);
            list.add(new byte[_128K]);
        }
    }
}
複製代碼

在控制檯輸入jconsole便可啓動JConsole客戶端

JConsole客戶端包括概覽、內存、線程、類、VM概要、MBean這大塊。

概覽:主要運行數據的概覽,包括堆內存,線程,類,CPU使用狀況四項信息的變化趨勢圖

內存:JDK爲1.8,使用的垃圾收集器爲ParallerScavenge+Parallel Old,能夠監視堆內存以及其中各個區域(Eden區,Survivor區,老年代)的變化趨勢,還能夠監視非堆(元空間)的內存變化趨勢,至關於命令行中的jstat

線程:能夠查看當前程序有哪些線程在運行,單機能夠查看線程的堆棧信息,至關於命令行工具的jstack,其左下角還有檢測死鎖的按鈕。

類:如圖所示,顯示了系統以及裝載的類數量。在詳細信息欄中,還顯示了已卸載的類數量。

VM概要:VM摘要:在VM摘要頁面,JConsole顯示了當前應用程序的運行環境。包括虛擬機類型、版本、堆信息以及虛擬機參數等。至關於命令行工具中的jinfo命令

示例二:JConcle示例死循環、阻塞等待、死鎖現象

import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class DEMO08 {

    public static void main(String[] args) throws IOException {
        System.in.read();
        System.out.println("開啓死循環線程");
        whileTureThread();

        System.in.read();
        System.out.println("開啓等待線程");
        waitThread();

        System.in.read();
        System.out.println("開啓死鎖線程");
        deadLock();

    }

    /** * 死循環線程 */
    private static void whileTureThread() {
        new Thread(() -> {
            while (true) {

            }
        }, "whileTrueThread").start();

    }

    /** * 等待線程 */
    private static void waitThread() {
        new Thread(() -> {
            synchronized (DEMO08.class) {
                try {
                    DEMO08.class.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"waitThread").start();
    }


    /** * 模擬死鎖現象 */
    private static void deadLock() {
        String A = "A";
        String B = "B";
        new Thread(() -> {
            synchronized (A) {
                try {
                    //睡2秒
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (B) {
                    System.out.println("拿到B鎖");
                }
            }
        }, "A").start();

        new Thread(() -> {
            synchronized (B) {
                try {
                    //睡2秒
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (A) {
                    System.out.println("拿到A鎖");
                }
            }
        }, "B").start();
    }
}
複製代碼

先在控制檯回車開啓死循環線程,觀察cpu佔用率狀況,可見CPU佔用一直居高不下

在去控制檯回車開啓等待線程觀察線程狀況,經過查看堆棧信息能夠定位到具體哪一行

在去控制檯回車開啓死鎖線程觀察線程狀況,經過查看堆棧信息能夠發現A線程在等待B的鎖,B線程在等待A的鎖

控制檯打印狀況如圖:

visualvm

仍是使用jconcle中示例二的代碼,此次在終端輸入jvisualvm便可進入。jvisualvm使用方式與jconsole有些類似。先開啓死循環觀察其cpu使用狀況,能夠看到也是高居不下,且比較穩定。

查看等待線程:黃色表明的是等待線程,點擊線程Dump,便可查看線程的堆棧信息

查看死鎖線程,當開啓死鎖線程後,visualvm能夠當即檢測到,點擊線程Dump,生成快照文件去查看堆棧詳情。

參考連接

JDK經常使用命令行工具
黑馬虛擬機性能分析經常使用工具

相關文章
相關標籤/搜索