JVM效能調優監控工具jps、jstack、jmap、jhat、jstat、hprof使用詳解,以及例子
現實企業級Java開發中,有時候我們會碰到下面這些問題:
OutOfMemoryError,記憶體不足
記憶體洩露
執行緒死鎖
鎖爭用(Lock Contention)
Java程序消耗CPU過高
......
這些問題在日常開發中可能被很多人忽視(比如有的人遇到上面的問題只是重啟伺服器或者調大記憶體,而不會深究問題根源),但能夠理解並解決這些問題是Java程式設計師進階的必備要求。本文將對一些常用的JVM效能調優監控工具進行介紹,希望能起拋磚引玉之用。本文參考了網上很多資料,難以一一列舉,在此對這些資料的作者表示感謝!關於JVM效能調優相關的資料,請參考文末。
A、 jps(Java Virtual Machine Process Status Tool)
jps主要用來輸出JVM中執行的程序狀態資訊。語法格式如下:
?1 |
jps [options] [hostid]
|
如果不指定hostid就預設為當前主機或伺服器。
命令列引數選項說明如下:
?1 2 3 4 |
-q 不輸出類名、Jar名和傳入main方法的引數 -m 輸出傳入main方法的引數
-l 輸出main類或Jar的全限名
-
v
輸出傳入JVM的引數
|
比如下面:
?1 2 3 4 5 6 7 8 |
[email protected]:/
# jps -m -l
2458 org.artifactory.standalone.main.Main
/usr/local/artifactory-2
.2.5
/etc/jetty
.xml
29920 com.sun.tools.hat.Main -port 9998
/tmp/dump
.dat
3149 org.apache.catalina.startup.Bootstrap start
30972 sun.tools.jps.Jps -m -l
8247 org.apache.catalina.startup.Bootstrap start
25687 com.sun.tools.hat.Main -port 9999 dump.dat
21711 mrf-center.jar
|
B、 jstack
jstack主要用來檢視某個Java程序內的執行緒堆疊資訊。語法格式如下:
?1 2 3 |
jstack [option] pid
jstack [option] executable core
jstack [option] [server-
id
@]remote-
hostname
-or-ip
|
命令列引數選項說明如下:
?1 2 |
-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:
?1 2 |
[email protected]:/
# 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的執行緒,用
?1 |
printf
"%x\n"
21742
|
得到21742的十六進位制值為54ee,下面會用到。
OK,下一步終於輪到jstack上場了,它用來輸出程序21711的堆疊資訊,然後根據執行緒ID的十六進位制值grep,如下:
?1 2 |
[email protected]:/
# jstack 21711 | grep 54ee
"PollIntervalRetrySchedulerThread"
prio=10 tid=0x00007f950043e000 nid=0x54ee
in
Object.wait() [0x00007f94c6eda000]
|
可以看到CPU消耗在PollIntervalRetrySchedulerThread這個類的Object.wait(),我找了下我的程式碼,定位到下面的程式碼:
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// 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檢視記憶體使用情況與生成heapdump
如果想分析自己的JAVA Application時,可以使用jmap程式來生成heapdump文例:
jmap -heap 1234 (1234為程序號)
jmap是JDK自帶的一個工具,非常小巧方便,其支援引數如下:
-heap:列印heap空間的概要,這裡可以粗略的檢驗heap空間的使用情況。
例:
jmap -heap 12345
輸出:
Attaching to process ID 2657, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 1.5.0_16-b02
using thread-local object allocation.
Mark Sweep Compact GC
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 67108864 (64.0MB)
NewSize = 655360 (0.625MB)
MaxNewSize = 4294901760 (4095.9375MB)
OldSize = 1441792 (1.375MB)
NewRatio = 12
SurvivorRatio = 8
PermSize = 8388608 (8.0MB)
MaxPermSize = 67108864 (64.0MB)
Heap Usage:
New Generation (Eden + 1 Survivor Space):----------------------------------------新生代區
capacity = 4521984 (4.3125MB)
used = 1510200 (1.4402389526367188MB)
free = 3011784 (2.8722610473632812MB)
33.39684527853261% used
Eden Space:--------------------------------------------------------------------伊甸園區
capacity = 4063232 (3.875MB)
used = 1495992 (1.4266891479492188MB)
free = 2567240 (2.4483108520507812MB)
36.81778446320565% used
From Space:-------------------------------------------------------------------年輕代(倖存者樂園1)
capacity = 458752 (0.4375MB)
used = 14208 (0.0135498046875MB)
free = 444544 (0.4239501953125MB)
3.0970982142857144% used
To Space:-----------------------------------------------------------------------------年輕代(倖存者樂園2)
capacity = 458752 (0.4375MB)
used = 0 (0.0MB)
free = 458752 (0.4375MB)
0.0% used
concurrent mark-sweep generation:-------------------------------------------------老年代
capacity = 8589934592 (8192.0MB)
used = 0 (0.0MB)
free = 8589934592 (8192.0MB)
0.0% used
Perm Generation:----------------------------------------------------------------------永久代
capacity = 11796480 (11.25MB)
used = 11712040 (11.169471740722656MB)
free = 84440 (0.08052825927734375MB)
99.28419325086806% used
以上的輸出很簡單,第四行起開始輸出此程序我們的JAVA使用的環境。
Heap Configuration,指在我們啟動時設定的一些JVM引數。像最大使用記憶體大小,年老代,年青代,持久代大小等。有這個可以很簡單的檢視本程序的記憶體使用情況。也許程序佔用的總記憶體比較多,但我們在這裡可以看到真正用到的並沒有多少,很多都是"Free"。記憶體使用的堆積大多在老年代,記憶體池露始於此,所以要格外關心“tenured generation”。
-heap:format=b:產生一個HeapDump檔案,此為生成heapdump檔案的重要引數。
例:jmap -heap:format=b 2657
會產生一個heap.bin的heapdump檔案。
需要注意的是,此生成heapdump的引數為JDK1.5,在1.6中的格式為:
jmap -dump:live,format=b,file=xxx 2657
這裡更加強大一些,可以指定是存活的物件,還有生成heapdump的檔名。
-histo:這裡會生成一個類的統計報表,此表簡單無比,如顯示什麼類有多少個例項,共佔了多少位元組等,如下:
Size Count Class description
-------------------------------------------------------
8394352 105 long[]
8293192 57202 char[]
7834776 14157 byte[]
6713592 53743 * ConstMethodKlass
4194320 1 com.xjawa.cms5server.Kontent[]
4055072 12319 int[]
3291104 85082 * SymbolKlass
3016040 53743 * MethodKlass
2774936 4253 * ConstantPoolKlass
1871480 4253 * InstanceKlassKlass
1811808 3990 * ConstantPoolCacheKlass
1488672 62028 java.lang.String
1203280 13258 java.lang.Object[]
-permstat:列印一些持久代上的記憶體使用狀態,有“活”的,有“死”的。
-h 或者 -help:檢視jmap所有可用命令及作用。
jhat
JVM Heap Analysis Tool命令是與jmap搭配使用,用來分析jmap生成的dump,jhat內建了一個微型的HTTP/HTML伺服器,生成dump的分析結果後,可以在瀏覽器中檢視。在此要注意,一般不會直接在伺服器上進行分析,因為jhat是一個耗時並且耗費硬體資源的過程,一般把伺服器生成的dump檔案複製到本地或其他機器上進行分析。【記憶體分析】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
[[email protected] bin]
# jhat -help
Usage: jhat [-stack <bool>] [-refs <bool>] [-port <port>] [-baseline <
file
>] [-debug <int>] [-version] [-h|-help] <
file
>
-J<flag> Pass <flag> directly to the runtime system. For
example, -J-mx512m to use a maximum heap size of 512MB
-stack
false
: Turn off tracking object allocation call stack.
-refs
false
: Turn off tracking of references to objects
-port <port>: Set the port
for
the HTTP server. Defaults to 7000
-exclude <
file
>: Specify a
file
that lists data members that should
be excluded from the reachableFrom query.
-baseline <
file
>: Specify a baseline object dump. Objects
in
both heap dumps with the same ID and same class will
be marked as not being
"new"
|