JVM調優專題-JVM調試工具

目錄

JVM圖形化監控和調優工具

JConsole

JvisualVm

Jvmstat

YourKit

JVM命令行監控工具

jps(JVM Process Status Tool)

jstack

jmap(Memory Map)和jhat(Java Heap Analysis Tool)

jstat(JVM統計監測工具)


 

當系統遇到一些問題或者異常的時候,我們往往會查看系統日誌、JVM堆棧、GC日誌,或者查看線程快照、堆轉儲快照等信息,然後進行一個客觀的分析,最後找到問題。而查看這些最常用的就是JVM自帶的監控分析工具。

JVM圖形化監控和調優工具

JConsole

JConsole 是一個基於JMX 的圖形監控工具,用於連接正在運行的JVM,可以以圖表化的形式顯示各種數據,並可通過遠程連接監視遠程的服務器VM 情況,此類工具可以較直觀觀察各種變化,但比較耗費資源。

在JDK 1.5之後JConsole 已經成爲JDK 自帶監控工具,只需要在命令行狀態下輸入jconsole,就可以開啓監控界面

jconsole

 

可以選擇遠程監控或者本地監控

 

從jconsole 中可以不光光監控到內存情況,還可以監控例如:線程,類,JVM參數等等高級信息。jconsole 還可以根據內存等使用情況手動執行GC 清理,這給我們的程序監控與良好運行帶來了很大的便利。值得注意的是jconsole可以同時監控多個JVM 進程,在jconsole 中可以輕鬆的切換監控界面。

  • 概述選項(Overview):監控JVM和一些監控變量的信息。
  • 內存選項(Memory):內存使用信息
  • 線程選項(Threads):線程使用信息
  • 類選項(Classes):類調用信息
  • VM摘要(VM Summary):JVM的信息
  • MBean選項(MBeans):所有MBean 的信息MBean 展示了所有以一般形式註冊到JVM 上的MBean 。MBean 允許你獲取所有的平臺信息,包括那些不能從其他標籤頁獲取到的信息。注意,其他標籤頁上的一些信息也在MBean 這裏顯示。另外,你可以使用 MBean 標籤管理你自己的應用的MBean。

JvisualVm

JDK1.6 中Java 引入了一個新的可視化的JVM 監控工具:Java VisualVM。 運行VisualVM 非常簡單,只需在命令行狀態下輸入:

jvisualvm

 

“本地”列表下列出在本機運行的Java 程序的資源佔用情況,如果本地有Java程序在運行的話啓動VisualVM 即可看到相應的程序名,點擊程序名打開相應的資源監控菜單,以圖形的形式列出程序所佔用的CPU、Heap、PermGen、類、線程的 統計信息

Jvmstat

圖形版的jvmstat需要去官網下載安裝包,使用jvmstat 之前需要配置相應環境變量,環境變量配置如下:

JVMSTAT_HOME:jvmstat安裝目錄 

JVMSTAT_JAVA_HOME:JDK所在目錄,與JAVA_HOME值相同 

配置好兩個環境變量之後就可以運行jvmstat 了,運行命令爲:

visualgc pid

 

http://dl2.iteye.com/upload/attachment/0088/0299/7eb99a1b-3fb0-338d-9c81-f2ea0049d38a.png?_=4635935

從jvmstat 中可以清晰的觀察到彙編,加載,垃圾回收消耗的時間與各區域內存使用情況,在圖中s0與s1的內存使用永遠都是相斥的,即至多隻有一個會在使用。所以jvmstat 只能作爲一款基本的圖形監控工具。

jvmstat 作爲一款基本的JVM 圖形化監控工具,優點就是簡單易用,我們可以非常直觀的觀察堆內存的使用情況,當然僅僅爲堆內存,所以jvmstat 具有一定的侷限性。

 

YourKit

YourKit 是一個用於分析Java 與.NET 應用程序的智能工具,YourKit Java Profiler 已經被IT 專業人士與分析師公認爲最好的分析工具。通過YourKit 技術解決方案可以以非常高的的專業水平分析出CPU 與內存使用情況。

YourKit Java Profiler 還獲得了Java Developer’s Journal(Java 開發者雜誌)的編輯選擇獎,其功能的強大可見一斑。

YourKit 網站官方:http://www.yourkit.com

YourKit Java Profiler 下載地址:http://www.yourkit.com/download/index.jsp

YourKit Java Profiler 提供了Java 與.NET 兩種語言的支持,並且支持基本所有操作系統。

http://dl2.iteye.com/upload/attachment/0088/6468/69ac01fb-276f-30a9-a620-5515a9d34696.png?_=4635935

監控界面

http://dl2.iteye.com/upload/attachment/0088/6489/1b687bff-a292-3870-8172-f102e279ef49.png?_=4635935

 

還可以打開內存管理界面,查看JVM 中各種內存的佔有情況

http://dl2.iteye.com/upload/attachment/0088/6491/91699d50-cd50-3e01-8f13-0426a9105974.png?_=4635935

 

JVM命令行監控工具

JDK本身提供了很多方便的JVM性能調優監控工具,除了集成式的VisualVM和jConsole外,還有jps、jstack、jmap、jhat、jstat等小巧的工具。

jps(JVM Process Status Tool)

jps主要用來輸出JVM中運行的進程狀態信息。語法格式如下:

jps [options] [hostid]

 

如果不指定hostid就默認爲當前主機或服務器。命令行參數選項說明如下:

-q 不輸出類名、Jar名和傳入main方法的參數

-m 輸出傳入main方法的參數

-l 輸出main類或Jar的全限名

-v 輸出傳入JVM的參數

例如:

 

jstack

jstack主要用來查看某個Java進程內的線程堆棧信息。語法格式如下:

jstack [option] pid

jstack [option] executable core

jstack [option] [server-id@]remote-hostname-or-ip

命令行參數選項說明如下:

-l long listings

會打印出額外的鎖信息,在發生死鎖時可以用jstack -l pid來觀察鎖持有情況

-m mixed mode

不僅會輸出Java堆棧信息,還會輸出C/C++堆棧信息(比如Native方法)

 

jstack可以定位到線程堆棧,根據堆棧信息我們可以定位到具體代碼,所以它在JVM性能調優中使用得非常多。下面我們來一個實例找出某個Java進程中最耗費CPU的Java線程並定位堆棧信息,用到的命令有ps、top、printf、jstack、grep。

第一步先找出Java進程ID,我部署在服務器上的Java應用名稱爲mrf-center:

root@ubuntu:/# ps -ef | grep mrf-center | grep -v grep

root     21711     1  1 14:47 pts/3    00:02:10 java -jar mrf-center.jar

得到進程ID爲21711,第二步找出該進程內最耗費CPU的線程,可以使用ps -Lfp pid或者ps -mp pid -o THREAD, tid, time或者top -Hp pid,我這裏用第三個,輸出如下:

 

TIME列就是各個Java線程耗費的CPU時間,CPU時間最長的是線程ID爲21742的線程,用  :printf "%x\n" 21742得到21742的十六進制值爲54ee,下面會用到。

OK,下一步終於輪到jstack上場了,它用來輸出進程21711的堆棧信息,然後根據線程ID的十六進制值grep,如下:

root@ubuntu:/# jstack 21711 | grep 54ee

"PollIntervalRetrySchedulerThread" prio=10 tid=0x00007f950043e000 nid=0x54ee in Object.wait() [0x00007f94c6eda000]

可以看到CPU消耗在PollIntervalRetrySchedulerThread這個類的Object.wait(),我找了下我的代碼,定位到下面的代碼:


     // Idle wait

    getLog().info("Thread [" + getName() + "] is idle waiting...");

    schedulerThreadState = PollTaskSchedulerThreadState.IdleWaiting;

    long now = System.currentTimeMillis();

    long waitTime = now + getIdleWaitTime();

    long timeUntilContinue = waitTime - now;

    synchronized(sigLock) {

        try {

            if(!halted.get()) {

                sigLock.wait(timeUntilContinue);

            }

        }

        catch (InterruptedException ignore) {

        }

    }

它是輪詢任務的空閒等待代碼,上面的sigLock.wait(timeUntilContinue)就對應了前面的Object.wait()。

 

jmap(Memory Map)和jhat(Java Heap Analysis Tool)

jmap用來查看堆內存使用狀況,一般結合jhat使用。jmap語法格式如下,如果運行在64位JVM上,可能需要指定-J-d64命令選項參數。:

jmap [option] pid

jmap [option] executable core

jmap [option] [server-id@]remote-hostname-or-ip

 

打印進程的類加載器和類加載器加載的持久代對象信息,輸出:類加載器名稱、對象是否存活(不可靠)、對象地址、父類加載器、已加載的類大小等信息,如下圖:

jmap -permstat pid

打印進程的類加載器和類加載器加載的持久代對象信息,輸出:類加載器名稱、對象是否存活(不可靠)、對象地址、父類加載器、已加載的類大小等信息,如下圖:

使用jmap -heap pid查看進程堆內存使用情況,包括使用的GC算法、堆配置參數和各代中堆內存使用情況。比如下面的例子:

 

使用jmap -histo[:live] pid查看堆內存中的對象數目、大小統計直方圖,如果帶上live則只統計活對象,如下:

 

class name是對象類型,說明如下:

B  byte

C  char

D  double

F  float

I  int

J  long

Z  boolean

[  數組,如[I表示int[]

[L+類名 其他對象

還有一個很常用的情況是:用jmap把進程內存使用情況dump到文件中,再用jhat分析查看。jmap進行dump命令格式如下:

jmap -dump:format=b,file=dumpFileName

我一樣地對上面進程ID爲4972進行Dump:

[root@dragon ~]# jmap -dump:format=b,file=/tmp/dump.dat 4972

Dumping heap to /tmp/dump.dat ...

Heap dump file created

 

dump出來的文件可以用MAT、VisualVM等工具查看,這裏用jhat查看:

  然後就可以在瀏覽器中輸入主機地址:9998查看了。

 

jstat(JVM統計監測工具)

語法格式如下:

jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]

vmid是虛擬機ID,在Linux/Unix系統上一般就是進程ID。interval是採樣時間間隔。count是採樣數目。比如下面輸出的是GC信息,採樣時間間隔爲250ms,採樣數爲4:

[root@dragon ~]# jstat -gc 4972 250 4

 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT  

6400.0 6400.0  0.0    0.0   51520.0  24985.4   128432.0   77058.1   100224.0 97331.9 11648.0 11098.7   2952   19.320   6      0.983   20.303

6400.0 6400.0  0.0    0.0   51520.0  24985.4   128432.0   77058.1   100224.0 97331.9 11648.0 11098.7   2952   19.320   6      0.983   20.303

6400.0 6400.0  0.0    0.0   51520.0  24985.4   128432.0   77058.1   100224.0 97331.9 11648.0 11098.7   2952   19.320   6      0.983   20.303

6400.0 6400.0  0.0    0.0   51520.0  24985.4   128432.0   77058.1   100224.0 97331.9 11648.0 11098.7   2952   19.320   6      0.983   20.303

要明白上面各列的意義,先看JVM堆內存佈局:

http://static.open-open.com/lib/uploadImg/20140128/20140128214841_435.jpg

可以看出:

堆內存 = 年輕代 + 年老代 + 永久代

年輕代 = Eden區 + 兩個Survivor區(From和To)

現在來解釋各列含義:

S0C、S1C、S0U、S1U:Survivor 0/1區容量(Capacity)和使用量(Used)

EC、EU:Eden區容量和使用量

OC、OU:年老代容量和使用量

PC、PU:永久代容量和使用量

YGC、YGT:年輕代GC次數和GC耗時

FGC、FGCT:Full GC次數和Full GC耗時

GCT:GC總耗時

 

 

 

 

 

 

 

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