JVM性能監控與故障處理工具

要查看哪些進程佔用了較多的資源(如CPU、內存、磁盤IO等),Linux下使用的最頻繁的一個命令是top,以下圖所示html

 這個就至關於windows下的任務管理器,可以簡單的描述每一個進程佔用的資源信息,包含CPU、磁盤、內存等信息,按1能夠將CPU拆解,看單個CPU的運行信息。使用ps –ef | grep 進程名能夠查看對應進程的簡單信息,如ps –ef|grep java,以下圖所示:java

其實JDK已經爲咱們提供了不少很好的針對Java的性能監控工具,下面咱們就來一塊兒看一下JDK都爲咱們提供了哪些性能檢測工具。linux

JDK的命令行工具

Jps(JVM Process Status Tools)

Jps是參照Unix系統的取名規則命名的,而他的功能和ps的功能相似,能夠列舉正在運行的虛擬機進程並顯示虛擬機執行的主類以及這些進程的惟一ID(LVMID,對應本機來講和PID相同),他的用法以下:web

Jps [option] [hostid]windows

其中hostid默認爲本機,而option選項包含如下選項瀏覽器

Option緩存

Function服務器

-qoracle

只輸出LVMIDapp

-m

輸出JVM啓動時傳給主類的方法

-l

輸出主類的全名,若是是Jar則輸出jar的路徑

-v

輸出JVM的啓動參數

 

 

jstat(JVM Statistics Monitoring Tools)

Jstat主要用於監控虛擬機的各類運行狀態信息,如類的裝載、內存、垃圾回收、JIT編譯器等。在沒有GUI的服務器上,這款工具是首選的一款監控工具。其用法以下:

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

參數interval和count分別表示查詢間隔和查詢次數,如每1毫秒查詢一次進程20445的垃圾回收狀況,監控20次,命令以下所示:

jstat –gc 20445 1 20 

 相關的輸出參數介紹可參照官方的說明(注:網址連接請點擊此處

選項option表明用戶須要查詢的虛擬機的信息,主要分爲3類:類裝載、垃圾回收和運行期的編譯狀況,具體以下表所示:

Option

Function

-class

監視類的裝載、卸載數量以及類的裝載總空間和耗費時間等

-gc

監視Java堆,包含eden、2個survivor區、old區和永久帶區域的容量、已用空間、GC時間合計等信息

-gccapcity

監視內容與-gc相同,但輸出主要關注Java區域用到的最大和最小空間

-gcutil

監視內容與-gc相同,但輸出主要關注已使用空間佔總空間的百分比

-gccause

-gcutil輸出信息相同,額外輸出致使上次GC產生的緣由

-gcnew

監控新生代的GC狀況

-gcnewcapacity

-gcnew監控信息相同,輸出主要關注使用到的最大和最小空間

-gcold

監控老生代的GC狀況

-gcoldcapacity

-gcold監控信息相同,輸出主要關注使用到的最大和最小空間

-gcpermcapacity

輸出永久帶用到的最大和最小空間

-compiler

輸出JIT編譯器編譯過的方法、耗時信息

-printcompilation

輸出已經被JIT編譯的方法

顯示內容說明以下(部分結果是經過其餘其餘參數顯示的,暫不說明):
         S0C:年輕代中第一個survivor(倖存區)的容量 (字節) 
         S1C:年輕代中第二個survivor(倖存區)的容量 (字節) 
         S0U:年輕代中第一個survivor(倖存區)目前已使用空間 (字節) 
         S1U:年輕代中第二個survivor(倖存區)目前已使用空間 (字節) 
         EC:年輕代中Eden(伊甸園)的容量 (字節) 
         EU:年輕代中Eden(伊甸園)目前已使用空間 (字節) 
         OC:Old代的容量 (字節) 
         OU:Old代目前已使用空間 (字節) 
         PC:Perm(持久代)的容量 (字節) 
         PU:Perm(持久代)目前已使用空間 (字節) 
         YGC:從應用程序啓動到採樣時年輕代中gc次數 
         YGCT:從應用程序啓動到採樣時年輕代中gc所用時間(s) 
         FGC:從應用程序啓動到採樣時old代(全gc)gc次數 
         FGCT:從應用程序啓動到採樣時old代(全gc)gc所用時間(s) 
         GCT:從應用程序啓動到採樣時gc用的總時間(s) 
         NGCMN:年輕代(young)中初始化(最小)的大小 (字節) 
         NGCMX:年輕代(young)的最大容量 (字節) 
         NGC:年輕代(young)中當前的容量 (字節) 
         OGCMN:old代中初始化(最小)的大小 (字節) 
         OGCMX:old代的最大容量 (字節) 
         OGC:old代當前新生成的容量 (字節) 
         PGCMN:perm代中初始化(最小)的大小 (字節) 
         PGCMX:perm代的最大容量 (字節)   
         PGC:perm代當前新生成的容量 (字節) 
         S0:年輕代中第一個survivor(倖存區)已使用的佔當前容量百分比 
         S1:年輕代中第二個survivor(倖存區)已使用的佔當前容量百分比 
         E:年輕代中Eden(伊甸園)已使用的佔當前容量百分比 
         O:old代已使用的佔當前容量百分比 
         P:perm代已使用的佔當前容量百分比 
         S0CMX:年輕代中第一個survivor(倖存區)的最大容量 (字節) 
         S1CMX :年輕代中第二個survivor(倖存區)的最大容量 (字節) 
         ECMX:年輕代中Eden(伊甸園)的最大容量 (字節) 
         DSS:當前須要survivor(倖存區)的容量 (字節)(Eden區已滿) 
         TT: 持有次數限制 
         MTT : 最大持有次數限制 

jinfo(JVM configuration Info for Java)

Jinfo的做用是實時查看虛擬機的各項參數信息jps –v能夠查看虛擬機在啓動時被顯式指定的參數信息,可是若是你想知道默認的一些參數信息呢?除了去查詢對應的資料之外,jinfo就顯得很重要了jinfo的用法以下:

Jinfo [option] pid

 jinfo –sysprops {pid}

還有不少參數信息,咱們能夠看到除了咱們顯式指定的參數信息之外,JVM的默認參數盡收眼底。同時,從JDK1.6之後,jinfo加入了運行時修改參數信息的能力,可使用-flag [+|-]name 或者-flag name=value來修改一部分運行期能夠寫入的虛擬機參數。更多信息可參考官方文檔

jmap(JVM Memory Map for Java)

Jmap用於生成堆快照(heapdump)。固然咱們有不少方法能夠取到對應的dump信息,如咱們經過JVM啓動時加入啓動參數 –XX:HeapDumpOnOutOfMemoryError參數,可讓JVM在出現內存溢出錯誤的時候自動生成dump文件,亦能夠經過-XX:HeapDumpOnCtrlBreak參數,在運行時使用ctrl+break按鍵生成dump文件,固然咱們也可使用kill -3 pid的方式去恐嚇JVM生成dump文件。Jmap的做用不只僅是爲了獲取dump文件,還能夠用於查詢finalize執行隊列、Java堆和永久帶的詳細信息,如空間使用率、垃圾回收器等。其運行格式以下:

Jmap [option] vmip

Option的信息以下表所示

Option

Function

-dump

生成對應的dump信息,用法爲-dump:[live,]format=b,file={fileName}

-finalizerinfo

顯示在F-Queue中等待的Finalizer方法的對象(只在linux下生效)

-heap

顯示堆的詳細信息、垃圾回收器信息、參數配置、分代詳情等

-histo

顯示堆棧中的對象的統計信息,包含類、實例數量和合計容量

-permstat

ClassLoder爲統計口徑顯示永久帶的內存狀態

-F

當虛擬機對-dump無響應時可以使用這個選項強制生成dump快照

示例:jmap -dump:format=b,file=yhj.dump 20445

 

 jhat(JVM Heap Analysis Tool)

Jhat是用來分析dump文件的一個微型的HTTP/HTML服務器,它能將生成的dump文件生成在線的HTML文件,讓咱們能夠經過瀏覽器進行查閱,然而實際中咱們不多使用這個工具,由於通常服務器上設置的堆、棧內存都比較大,生成的dump也比較大,直接用jhat容易形成內存溢出,而是咱們大部分會將對應的文件拷貝下來,經過其餘可視化的工具進行分析。其用法以下:

Jhat {dump_file}

執行命令後,咱們看到系統開始讀取這段dump信息,當系統提示Server is ready的時候,用戶能夠經過在瀏覽器鍵入http://ip地址:7000進行查詢。

咱們能夠看到剛纔生成的dump文件有多大

 

 咱們來生成如下看看!

jhat yhj.dump

 

 //……..

 

 而後咱們啓動瀏覽器查看

 咱們能夠看到,很詳細的類信息都被抓了出來

 

 

jstack(JVM Stack Trace for java)

Jstack用於JVM當前時刻的線程快照,又稱threaddump文件,它是JVM當前每一條線程正在執行的堆棧信息的集合。生成線程快照的主要目的是爲了定位線程出現長時間停頓的緣由,如線程死鎖、死循環、請求外部時長過長致使線程停頓的緣由。經過jstack咱們就能夠知道哪些進程在後臺作些什麼,在等待什麼資源等!其運行格式以下:

Jstack [option] vmid

相關的option和function以下表所示

Option

Function

-F

當正常輸出的請求不響應時強制輸出線程堆棧

-l

除堆棧信息外,顯示關於鎖的附加信息

-m

顯示native方法的堆棧信息

示例:jstack -l 20445

 

 從JDK1.5之後,java.lang.Thread類增長了一個getAllStackTraces()方法用於獲取虛擬機中的StackTraceElement對象,咱們能夠經過很簡單的代碼獲取對應JVM的信息,下面是一個簡單的示例:

package com.yhj.monitor;

import java.util.Map;
import java.util.Set;
/**
 * @Described:線程監控器
 * @author YHJ create at 2012-3-26 下午05:20:18
 * @FileNmae com.yhj.monitor.Threadmonitor.java
 */
public class Threadmonitor {

    public static void main(String[] args) {
       Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
       Set<Thread> set = map.keySet();
       for(Thread thread : set){
           System.out.println("檢測到線程["+thread.getId()+":"+thread.getName()+"],線程詳細信息:");
           for(StackTraceElement trace:map.get(thread)){
              System.out.println(trace);
           }
       }
    }
}

 

一次運行結果以下:

 若是咱們把這個寫入一個web工程的一個監控頁面上,一個小的監控線程的程序就有了, !

JDK的可視化工具

介紹了前面幾個命令,你們也許還在擔憂如何記住這麼多詳細的參數,其實JDK爲咱們提供了更爲強大的GUI的監控工具,囊括了上面全部的監控工具的功能,同時還增長了不少工具方便咱們的故障分析與性能監控!

JDK1.5開始,JDK加入了可視化監控工具Jconsole,而從JDK1.6u7之後加了多功能於一體的可視化監控工具VisualVM。下面咱們來逐一看一下!

JConsole(JVM Monitoring and management console)

JDK的bin目錄下,咱們很容易找到jconsole.exe這個程序,雙擊便可啓動!

 這款工具既能夠實現本地監控,亦能夠實現遠程監控。.

啓動後界面如圖所示:

 

 咱們能夠清楚的查看對應的CPU、內存、類和一塊兒其餘的詳細信息。

在內存的tab頁面,咱們能夠看到內存的變化。

 

 在線程tab,咱們能夠追蹤對應線程的變化狀況

 

 咱們來監控一段代碼

package com.yhj.monitor;
/**
 * @Described:死鎖演示
 * @author YHJ create at 2012-3-26 下午05:46:36
 * @FileNmae com.yhj.monitor.Deadlock.java
 */
public class Deadlock implements Runnable{
    private int a;
    private int b;
    public Deadlock(int a, int b) {
       super();
       this.a = a;
       this.b = b;
    }
    @Override
    public void run() {
       synchronized (Integer.valueOf(a)) {
           synchronized (Integer.valueOf(b)) {
              System.out.println("a+b="+(a+b));
           }
       }
    }
    public static void main(String[] args) {
       for(int i = 0; i < 1000; ++i){
           new Thread(new Deadlock(1, 2)).start();
           new Thread(new Deadlock(2, 1)).start();
       }
    }
}

 

這段代碼執行一段時間你會發現他不動了,以下圖所示:

 咱們使用Jconsole的線程tab,下面有一個檢測死鎖的按鈕,點擊一下

 

Jconsole很清楚的告訴咱們發生了死鎖,如上圖所示。而且明確的告訴咱們死鎖線程每一個線程都在幹什麼?什麼資源致使了死鎖的發生,很精確。

不少人還在迷惑,上段代碼怎麼可能發生死鎖的?每一個線程獨享一個a和一個b,互不相干,怎麼可能發生死鎖呢?

其實發生死鎖的緣由是咱們調用了Integer.valueOf()方法,這個方法是基於減小建立對象次數和節省內存設計的,出於這個的考慮,在[-128~127]之間的數字會被緩存掉,也就是咱們循環中傳輸了那麼多的1和2其實就返回的2個,當某個對象持有1,而另一個對象持有2的時候,第一個等待2的釋放,而第二個等待1的釋放,所以就發生了死鎖。其實這個程序的循環也是不須要的,2個線程就可能引起死鎖,可是程序執行太快,機率過小,加一個1000次的循環就是爲了增大這種機率。

VisualVM

VisualVM被稱爲是more in one的工具集,它能夠實現如下功能點:

一、  顯示虛擬機的進程以及進程的配置信息和環境信息(jps、jinfo)

二、  監視應用程序的CPU、內存、堆、方法區和線程信息(jstat、jstack)

三、  Dump以及分析dump的功能(jmap、jhat)

四、  離線程序快照:離線dump分析

五、  方法運行性能分析,找出調用最多,運行最長的方法塊

六、  Plugings動態擴展功能

VisualVM由於是基於netBean開發,所以天生就具備plug大量擴展的能力,咱們能夠經過他的插件頁面輕鬆安裝所須要的插件!

啓用VisualVM工具會很醒目的告訴咱們檢測到一個死鎖,而不須要咱們在Jconsole下手動啓用檢測。以下圖所示:

 

 VisualVM的插件安裝圖示以下圖所示:

 

 

 

 

 

 

 

 

 

  • jvisual(Java VisualVM)導入dump文件內存不足解決辦法

經過jvusual調整-Xmx參數:c:/program files/java/jdk1.6/lib/visualvm/etc/visualvm.conf

修改內容:-J-Xmx24m -J-Xmx256m

改成:-J-Xmx4096m -J-Xmx4096m 

驗證辦法:從新打開jvisual,點擊「本地」--VisualVM,查看JVM參數是否更新。

BTrace

 在VisualVM中有一個開源的,強大的插件,叫作BTrace。這是一個頗有意思的插件,假設這麼一種場景,某天你的程序忽然出現了某個差錯,可是有沒有寫日誌,怎麼辦呢?BTrace就能夠經過簡單的代碼注入,在你不重啓服務器的狀況下動態加入相關的日誌語句。相關示例請參見官方DEMO:https://hg.kenai.com/hg/btrace~hg/file/d31d25ebd48b/samples

 

 

 參考資料

深刻理解JVM—性能監控工具:http://blog.csdn.net/wuqiqing_1/article/details/52200000

周志明:深刻理解Java虛擬機:JVM高級特性與最佳實踐

相關文章
相關標籤/搜索