JDK監控和故障處理工具(深入理解Java虛擬機筆記)

JDK 命令行工具

jps

列出正在運行的虛擬機進程,並顯示虛擬機執行(main()函數所在主類)名稱 以及 這些進程的本地虛擬機唯一ID。

命令格式爲。

jps [ options ] [ hostid ]

其中選項option代表用戶希望查詢的虛擬機信息,主要分爲三類:類加載,垃圾收集,運行期編譯狀況,常用的option選項如下

如下圖所示,210636是本地虛擬機唯一ID。

(1)jps -l 輸出主類的全名

(2)jps -v 輸出虛擬機進程啓動時JVM參數

(3)jps -m 輸出傳遞給Java進程main函數的參數

 

jstat

監視虛擬機各種運行狀態信息。它可以顯示本地或遠程虛擬機進程中的類加載,內存,垃圾收集,即使編譯等運行時數據。

命令格式如下。參數interval和count代表查詢間隔和次數,若省略則只查詢一次,比如 jstat -gc 2764 250 20 意思爲每250毫秒查詢一次進程2764垃圾收集狀況,一共查詢20次

jstat [ option vmid [interval[s|ms] [count]] ]

如果是本地虛擬機進程,vmid與lvmid是一致的;若是遠程虛擬機進程,則vmid的格式應爲:

[protocol:][//]lvmid[@hostname[:port]/servername]

測試:監視一臺服務器的內存狀況:

jstat -gcutil 2764

S0      S1     E       O        P           YGC YGCT     FGC FGCT    GCT

0.00  0.00  6.20   41.42    47.20     16     0.105        3     0.472    0.577

服務器的新生代Eden使用了6.2%的空間,2個Survivor區(S0,S1)裏面爲空,老年代Old和永久代Permanent分別使用了41/42%和47.20%的空間。程序運行以來共發生Minor GC(YGC,表示Young GC)16次,總耗時0.105秒;發生Full GC(FGC,表示Full GC)3次,總耗時(FGCT,表示Full GC Time)爲0.472秒;所有GC總耗時(GCT,表示GC Time)爲0.577秒。

 

jinfo

實時查看和調增虛擬機各項參數。前面提到的jps命令的-v參數可以查看虛擬機啓動時顯示指定的參數列表,但如果想知道未被顯示指定的參數的系統默認值,可以使用jinfo的 -flag進行查詢。

測試:如果我們希望查看虛擬機是否使用了某個收集器,如下所示。結果是+表示使用的是CMS收集器;若冒號後面跟的是-,則表示不是使用給定的收集器

jinfo -flag UseConcMarkSweepGC 210636

-XX:+UseConcMarkSweepGC

測試:查詢CMSInitiatingOccupancyFraction參數值

jinfo -flag  CMSInitiatingOccupancyFraction 210636
-XX:CMSInitiatingOccupancyFraction=-1

 

jmap

生成堆存儲快照。同時也可以查詢finalize執行隊列,Java堆和方法區的信息(如空間使用率,當前使用的是哪種收集器等)。

測試:在F盤生成a.bin堆存儲快照(注:須在管理員模式下cmd)。可通過Visual 等工具分析文件

jmap -dump:format=b,file=F:\a.bin  210636

Dumping heap to F:\a.bin ...
Heap dump file created

 

jhat

與jmap搭配使用,用於分析其生成的堆轉儲快照。jhat內置一個微型的HTTP/Web服務器,使用戶可以在瀏覽器查看分析結果。

測試:http://localhost:7000/中查看前面生成的堆存儲快照

jhat f:\a.bin

...省略前面輸出

Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

 

 

jstack

生成虛擬機當前時刻的線程快照(當前虛擬機內每一條線程正在執行的方法堆棧的集合)。生成線程快照的目的是定位線程出現長時間聽到的原因,如線程間死鎖,死循環等。

測試:下面是一段死鎖代碼

public class JavaVM {
    private static Object resource1 = new Object();
    private static Object resource2 = new Object();

    public static void main(String[] args) throws Exception {
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resource1) {
                    System.out.println(Thread.currentThread() + "get resource1");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread() + "waiting get resource2");
                    synchronized (resource2) {
                        System.out.println(Thread.currentThread() + "get resource2");
                    }
                }
            }
        }, "線程 1").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resource2) {
                    System.out.println(Thread.currentThread() + "get resource2");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread() + "waiting get resource1");
                    synchronized (resource1) {
                        System.out.println(Thread.currentThread() + "get resource1");
                    }
                }
            }
        }, "線程 2").start();
    }
}

通過監視器jstack命令分析:

jstack 148688

Found one Java-level deadlock:
=============================
"線程 2":
  waiting to lock monitor 0x0000000002bfaf98 (object 0x000000076bc2a1b8, a java.lang.Object),
  which is held by "線程 1"
"線程 1":
  waiting to lock monitor 0x0000000002bf8708 (object 0x000000076bc2a1c8, a java.lang.Object),
  which is held by "線程 2"

Java stack information for the threads listed above:
===================================================
"??程 2":
        at JavaVM$2.run(JavaVM.java:47)
        - waiting to lock <0x000000076bc2a1b8> (a java.lang.Object)
        - locked <0x000000076bc2a1c8> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:745)
"線程 1":
        at JavaVM$1.run(JavaVM.java:29)
        - waiting to lock <0x000000076bc2a1c8> (a java.lang.Object)
        - locked <0x000000076bc2a1b8> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:745)

Found 1 deadlock.

 


JDK 可視化分析工具

JConsole:Java監視與管理控制檯

它的主要功能是通過JMX的MBean對系統進行信息收集和參數動態調整。

通過JDK/bin目錄下的jconsole.exe啓動JConsole後,會自動搜索出本機運行的所有虛擬機進程。它可以對遠程虛擬機進行監控

                                                                                         內存監控

jconsole可以顯示當前內存的詳細信息,包括堆內存,非堆內存,新生代,survior區等使用情況。

點擊 “執行CG”按鈕可以強制執行一個Full GC

 

                                                                                         線程監控

同樣,jconsole可以做一次類似可視化的jstack命令的線程監控

 

VisualVM:多合-故障處理工具

它是一個運行監視和故障處理的程序,可以做到:

  • 顯示虛擬機進程以及進程的配置、環境信息(jps、jinfo)。
  • 監視應用程序的 CPU、GC、堆、方法區以及線程的信息(jstat、jstack)。
  • dump 以及分析堆轉儲快照(jmap、jhat)。
  • 方法級的程序運行性能分析,找到被調用最多、運行時間最長的方法。

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章