這些問題在平常開發中可能被不少人忽視(好比有的人遇到上面的問題只是重啓服務器或者調大內存,而不會深究問題根源),但可以理解並解決這些問題是Java程序員進階的必備要求。本文將對一些經常使用的JVM性能調優監控工具進行介紹,但願能起拋磚引玉之用。本文參考了網上不少資料,難以一一列舉,在此對這些資料的做者表示感謝!關於JVM性能調優相關的資料,請參考文末。css
A、 jps(Java Virtual Machine Process Status Tool) html
jps主要用來輸出JVM中運行的進程狀態信息。語法格式以下:java
1
|
<code class=
"hljs css"
><span class=
"hljs-selector-tag"
>jps <span class=
"hljs-selector-attr"
>[options] <span class=
"hljs-selector-attr"
>[hostid]<
/span
><
/span
><
/span
><
/code
>
|
若是不指定hostid就默認爲當前主機或服務器。nginx
命令行參數選項說明以下:程序員
1
2
3
4
|
<code class=
"hljs haml"
>-<span class=
"ruby"
>q 不輸出類名、Jar名和傳入main方法的參數
-<span class=
"ruby"
>m 輸出傳入main方法的參數
-<span class=
"ruby"
>l 輸出main類或Jar的全限名
-<span class=
"ruby"
>
v
輸出傳入JVM的參數<
/span
><
/span
><
/span
><
/span
><
/code
>
|
好比下面:算法
1
2
3
4
5
6
7
8
|
<code class=
"hljs less"
>root<span class=
"hljs-variable"
>@ubuntu:/
# jps -m -l
<span class=
"hljs-number"
>2458 org.artifactory.standalone.main.Main
/usr/local/artifactory-
<span class=
"hljs-number"
>2.2.<span class=
"hljs-number"
>5
/etc/jetty
.xml
<span class=
"hljs-number"
>29920 com.sun.tools.hat.Main -port <span class=
"hljs-number"
>9998
/tmp/dump
.dat
<span class=
"hljs-number"
>3149 org.apache.catalina.startup.Bootstrap start
<span class=
"hljs-number"
>30972 sun.tools.jps.Jps -m -l
<span class=
"hljs-number"
>8247 org.apache.catalina.startup.Bootstrap start
<span class=
"hljs-number"
>25687 com.sun.tools.hat.Main -port <span class=
"hljs-number"
>9999 dump.dat
<span class=
"hljs-number"
>21711 mrf-center.jar<
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/code
>
|
B、 jstackshell
jstack主要用來查看某個Java進程內的線程堆棧信息。語法格式以下:apache
1
2
3
|
<code class=
"hljs css"
><span class=
"hljs-selector-tag"
>jstack <span class=
"hljs-selector-attr"
>[option] <span class=
"hljs-selector-tag"
>pid
<span class=
"hljs-selector-tag"
>jstack <span class=
"hljs-selector-attr"
>[option] <span class=
"hljs-selector-tag"
>executable <span class=
"hljs-selector-tag"
>core
<span class=
"hljs-selector-tag"
>jstack <span class=
"hljs-selector-attr"
>[option] <span class=
"hljs-selector-attr"
>[server-
id
@]<span class=
"hljs-selector-tag"
>remote-
hostname
-or-ip<
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/code
>
|
命令行參數選項說明以下:ubuntu
1
2
|
<code class=
"hljs haml"
>-<span class=
"ruby"
>l long listings,會打印出額外的鎖信息,在發生死鎖時能夠用jstack -l pid來觀察鎖持有狀況
-<span class=
"ruby"
>m mixed mode,不只會輸出Java堆棧信息,還會輸出C
/C
++堆棧信息(好比Native方法)<
/span
><
/span
><
/code
>
|
jstack能夠定位到線程堆棧,根據堆棧信息咱們能夠定位到具體代碼,因此它在JVM性能調優中使用得很是多。下面咱們來一個實例找出某個Java進程中最耗費CPU的Java線程並定位堆棧信息,用到的命令有ps、top、printf、jstack、grep。數組
第一步先找出Java進程ID,我部署在服務器上的Java應用名稱爲mrf-center:
1
2
|
<code class=
"hljs less"
>root<span class=
"hljs-variable"
>@ubuntu:/
# ps -ef | grep mrf-center | grep -v grep
root <span class=
"hljs-number"
>21711 <span class=
"hljs-number"
>1 <span class=
"hljs-number"
>1 <span class=
"hljs-number"
>14:<span class=
"hljs-number"
>47 pts/<span class=
"hljs-number"
>3 <span class=
"hljs-number"
>00:<span class=
"hljs-number"
>02:<span class=
"hljs-number"
>10 java -jar mrf-center.jar<
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/code
>
|
獲得進程ID爲21711,第二步找出該進程內最耗費CPU的線程,可使用ps -Lfp pid或者ps -mp pid -o THREAD, tid, time或者top -Hp pid,我這裏用第三個,輸出以下:
TIME列就是各個Java線程耗費的CPU時間,CPU時間最長的是線程ID爲21742的線程,用
1
|
<code class=
"hljs perl"
><span class=
"hljs-keyword"
>
printf
<span class=
"hljs-string"
>
"%x\n"
<span class=
"hljs-number"
>21742<
/span
><
/span
><
/span
><
/code
>
|
獲得21742的十六進制值爲54ee,下面會用到。
OK,下一步終於輪到jstack上場了,它用來輸出進程21711的堆棧信息,而後根據線程ID的十六進制值grep,以下:
1
2
|
<code class=
"hljs less"
>root<span class=
"hljs-variable"
>@ubuntu:/
# jstack <span class="hljs-number">21711 | grep <span class="hljs-number">54ee
<span class=
"hljs-string"
>
"PollIntervalRetrySchedulerThread"
prio=<span class=
"hljs-number"
>10 tid=<span class=
"hljs-number"
>0x00007f950043e000 nid=<span class=
"hljs-number"
>0x54ee
in
Object.wait() [<span class=
"hljs-number"
>0x00007f94c6eda000]<
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/code
>
|
能夠看到CPU消耗在PollIntervalRetrySchedulerThread這個類的Object.wait(),我找了下個人代碼,定位到下面的代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<code
class
=
"hljs java"
><span
class
=
"hljs-comment"
>
// Idle wait
getLog().info(<span
class
=
"hljs-string"
>
"Thread ["
+ getName() + <span
class
=
"hljs-string"
>
"] is idle waiting..."
);
schedulerThreadState = PollTaskSchedulerThreadState.IdleWaiting;
<span
class
=
"hljs-keyword"
>
long
now = System.currentTimeMillis();
<span
class
=
"hljs-keyword"
>
long
waitTime = now + getIdleWaitTime();
<span
class
=
"hljs-keyword"
>
long
timeUntilContinue = waitTime - now;
<span
class
=
"hljs-keyword"
>
synchronized
(sigLock) {
<span
class
=
"hljs-keyword"
>
try
{
<span
class
=
"hljs-keyword"
>
if
(!halted.get()) {
sigLock.wait(timeUntilContinue);
}
}
<span
class
=
"hljs-keyword"
>
catch
(InterruptedException ignore) {
}
}</span></span></span></span></span></span></span></span></span></span></code>
|
它是輪詢任務的空閒等待代碼,上面的sigLock.wait(timeUntilContinue)就對應了前面的Object.wait()。
C、 jmap(Memory Map)和jhat(Java Heap Analysis Tool)
jmap用來查看堆內存使用情況,通常結合jhat使用。
jmap語法格式以下:
1
2
3
|
<code class=
"hljs css"
><span class=
"hljs-selector-tag"
>jmap <span class=
"hljs-selector-attr"
>[option] <span class=
"hljs-selector-tag"
>pid
<span class=
"hljs-selector-tag"
>jmap <span class=
"hljs-selector-attr"
>[option] <span class=
"hljs-selector-tag"
>executable <span class=
"hljs-selector-tag"
>core
<span class=
"hljs-selector-tag"
>jmap <span class=
"hljs-selector-attr"
>[option] <span class=
"hljs-selector-attr"
>[server-
id
@]<span class=
"hljs-selector-tag"
>remote-
hostname
-or-ip<
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/code
>
|
若是運行在64位JVM上,可能須要指定-J-d64命令選項參數。
1
|
<code class=
"hljs tcl"
>jmap -permstat <span class=
"hljs-keyword"
>pid<
/span
><
/code
>
|
打印進程的類加載器和類加載器加載的持久代對象信息,輸出:類加載器名稱、對象是否存活(不可靠)、對象地址、父類加載器、已加載的類大小等信息,以下圖:
使用jmap -heap pid查看進程堆內存使用狀況,包括使用的GC算法、堆配置參數和各代中堆內存使用狀況。好比下面的例子:
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
<code class=
"hljs less"
>root<span class=
"hljs-variable"
>@ubuntu:/
# jmap -heap <span class="hljs-number">21711
Attaching to process ID <span class=
"hljs-number"
>21711, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is <span class=
"hljs-number"
>20.10-b01
using thread-
local
object allocation.
Parallel GC with <span class=
"hljs-number"
>4 thread(s)
Heap <span class=
"hljs-attribute"
>Configuration:
MinHeapFreeRatio = <span class=
"hljs-number"
>40
MaxHeapFreeRatio = <span class=
"hljs-number"
>70
MaxHeapSize = <span class=
"hljs-number"
>2067791872 (<span class=
"hljs-number"
>1972.0MB)
NewSize = <span class=
"hljs-number"
>1310720 (<span class=
"hljs-number"
>1.25MB)
MaxNewSize = <span class=
"hljs-number"
>17592186044415 MB
OldSize = <span class=
"hljs-number"
>5439488 (<span class=
"hljs-number"
>5.1875MB)
NewRatio = <span class=
"hljs-number"
>2
SurvivorRatio = <span class=
"hljs-number"
>8
PermSize = <span class=
"hljs-number"
>21757952 (<span class=
"hljs-number"
>20.75MB)
MaxPermSize = <span class=
"hljs-number"
>85983232 (<span class=
"hljs-number"
>82.0MB)
Heap <span class=
"hljs-attribute"
>Usage:
PS Young Generation
Eden <span class=
"hljs-attribute"
>Space:
capacity = <span class=
"hljs-number"
>6422528 (<span class=
"hljs-number"
>6.125MB)
used = <span class=
"hljs-number"
>5445552 (<span class=
"hljs-number"
>5.1932830810546875MB)
free
= <span class=
"hljs-number"
>976976 (<span class=
"hljs-number"
>0.9317169189453125MB)
<span class=
"hljs-number"
>84.78829520089286% used
From <span class=
"hljs-attribute"
>Space:
capacity = <span class=
"hljs-number"
>131072 (<span class=
"hljs-number"
>0.125MB)
used = <span class=
"hljs-number"
>98304 (<span class=
"hljs-number"
>0.09375MB)
free
= <span class=
"hljs-number"
>32768 (<span class=
"hljs-number"
>0.03125MB)
<span class=
"hljs-number"
>75.0% used
To <span class=
"hljs-attribute"
>Space:
capacity = <span class=
"hljs-number"
>131072 (<span class=
"hljs-number"
>0.125MB)
used = <span class=
"hljs-number"
>0 (<span class=
"hljs-number"
>0.0MB)
free
= <span class=
"hljs-number"
>131072 (<span class=
"hljs-number"
>0.125MB)
<span class=
"hljs-number"
>0.0% used
PS Old Generation
capacity = <span class=
"hljs-number"
>35258368 (<span class=
"hljs-number"
>33.625MB)
used = <span class=
"hljs-number"
>4119544 (<span class=
"hljs-number"
>3.9287033081054688MB)
free
= <span class=
"hljs-number"
>31138824 (<span class=
"hljs-number"
>29.69629669189453MB)
<span class=
"hljs-number"
>11.683876009235595% used
PS Perm Generation
capacity = <span class=
"hljs-number"
>52428800 (<span class=
"hljs-number"
>50.0MB)
used = <span class=
"hljs-number"
>26075168 (<span class=
"hljs-number"
>24.867218017578125MB)
free
= <span class=
"hljs-number"
>26353632 (<span class=
"hljs-number"
>25.132781982421875MB)
<span class=
"hljs-number"
>49.73443603515625% used
....<
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/code
>
|
使用jmap -histo[:live] pid查看堆內存中的對象數目、大小統計直方圖,若是帶上live則只統計活對象,以下:
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
27
28
29
30
31
32
33
34
35
36
37
|
<code class=
"hljs scss"
>root@ubuntu:/
# jmap -histo:live 21711 | more
num
#instances <span class="hljs-number">#bytes class name
----------------------------------------------
1: 38445 5597736 <constMethodKlass>
2: 38445 5237288 <methodKlass>
3: 3500 3749504 <constantPoolKlass>
4: 60858 3242600 <symbolKlass>
5: 3500 2715264 <instanceKlassKlass>
6: 2796 2131424 <constantPoolCacheKlass>
7: 5543 1317400 [I
8: 13714 1010768 [C
9: 4752 1003344 [B
10: 1225 639656 <methodDataKlass>
11: 14194 454208 java.lang.String
12: 3809 396136 java.lang.Class
13: 4979 311952 [S
14: 5598 287064 [[I
15: 3028 266464 java.lang.reflect.Method
16: 280 163520 <objArrayKlassKlass>
17: 4355 139360 java.util.HashMap<span class=
"hljs-variable"
>$Entry
18: 1869 138568 [Ljava.util.HashMap<span class=
"hljs-variable"
>$Entry;
19: <span class=
"hljs-number"
>2443 <span class=
"hljs-number"
>97720 java.util.LinkedHashMap<span class=
"hljs-variable"
>$Entry
<span class=
"hljs-number"
>20: <span class=
"hljs-number"
>2072 <span class=
"hljs-number"
>82880 java.lang.ref.SoftReference
<span class=
"hljs-number"
>21: <span class=
"hljs-number"
>1807 <span class=
"hljs-number"
>71528 [Ljava.lang.Object;
22: <span class=
"hljs-number"
>2206 <span class=
"hljs-number"
>70592 java.lang.ref.WeakReference
<span class=
"hljs-number"
>23: <span class=
"hljs-number"
>934 <span class=
"hljs-number"
>52304 java.util.LinkedHashMap
<span class=
"hljs-number"
>24: <span class=
"hljs-number"
>871 <span class=
"hljs-number"
>48776 java.beans.MethodDescriptor
<span class=
"hljs-number"
>25: <span class=
"hljs-number"
>1442 <span class=
"hljs-number"
>46144 java.util.concurrent.ConcurrentHashMap<span class=
"hljs-variable"
>$HashEntry
<span class=
"hljs-number"
>26: <span class=
"hljs-number"
>804 <span class=
"hljs-number"
>38592 java.util.HashMap
<span class=
"hljs-number"
>27: <span class=
"hljs-number"
>948 <span class=
"hljs-number"
>37920 java.util.concurrent.ConcurrentHashMap<span class=
"hljs-variable"
>$Segment
<span class=
"hljs-number"
>28: <span class=
"hljs-number"
>1621 <span class=
"hljs-number"
>35696 [Ljava.lang.Class;
29: <span class=
"hljs-number"
>1313 <span class=
"hljs-number"
>34880 [Ljava.lang.String;
30: <span class=
"hljs-number"
>1396 <span class=
"hljs-number"
>33504 java.util.LinkedList<span class=
"hljs-variable"
>$Entry
<span class=
"hljs-number"
>31: <span class=
"hljs-number"
>462 <span class=
"hljs-number"
>33264 java.lang.reflect.Field
<span class=
"hljs-number"
>32: <span class=
"hljs-number"
>1024 <span class=
"hljs-number"
>32768 java.util.Hashtable<span class=
"hljs-variable"
>$Entry
<span class=
"hljs-number"
>33: <span class=
"hljs-number"
>948 <span class=
"hljs-number"
>31440 [Ljava.util.concurrent.ConcurrentHashMap<span class=
"hljs-variable"
>$HashEntry;<
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/code
>
|
class name是對象類型,說明以下:
1
2
3
4
5
6
7
8
9
|
<code class=
"hljs java"
>B <span class=
"hljs-keyword"
>byte
C <span class=
"hljs-keyword"
>char
D <span class=
"hljs-keyword"
>double
F <span class=
"hljs-keyword"
>float
I <span class=
"hljs-keyword"
>int
J <span class=
"hljs-keyword"
>long
Z <span class=
"hljs-keyword"
>boolean
[ 數組,如[I表示<span class=
"hljs-keyword"
>int[]
[L+類名 其餘對象<
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/code
>
|
還有一個很經常使用的狀況是:用jmap把進程內存使用狀況dump到文件中,再用jhat分析查看。jmap進行dump命令格式以下:
1
|
<code class=
"hljs tcl"
>jmap -dump:<span class=
"hljs-keyword"
>
format
=b,<span class=
"hljs-keyword"
>
file
=dumpFileName <span class=
"hljs-keyword"
>pid<
/span
><
/span
><
/span
><
/code
>
|
我同樣地對上面進程ID爲21711進行Dump:
1
2
3
|
<code class=
"hljs less"
>root<span class=
"hljs-variable"
>@ubuntu:/
# jmap <span class="hljs-attribute">-dump:format=b,file=/tmp/dump.dat <span class="hljs-number">21711
Dumping heap to
/tmp/dump
.dat ...
Heap dump
file
created<
/span
><
/span
><
/span
><
/code
>
|
dump出來的文件能夠用MAT、VisualVM等工具查看,這裏用jhat查看:
1
2
3
4
5
6
7
8
9
10
|
<code class=
"hljs less"
>root<span class=
"hljs-variable"
>@ubuntu:/
# jhat -port <span class="hljs-number">9998 /tmp/dump.dat
Reading from
/tmp/dump
.dat...
Dump
file
created Tue Jan <span class=
"hljs-number"
>28 <span class=
"hljs-number"
>17:<span class=
"hljs-number"
>46:<span class=
"hljs-number"
>14 CST <span class=
"hljs-number"
>2014
Snapshot
read
, resolving...
Resolving <span class=
"hljs-number"
>132207 objects...
Chasing references, expect <span class=
"hljs-number"
>26 dots..........................
Eliminating duplicate references..........................
Snapshot resolved.
Started HTTP server on port <span class=
"hljs-number"
>9998
Server is ready.<
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/code
>
|
注意若是Dump文件太大,可能須要加上-J-Xmx512m這種參數指定最大堆內存,即jhat -J-Xmx512m -port 9998 /tmp/dump.dat。而後就能夠在瀏覽器中輸入主機地址:9998查看了:
上面紅線框出來的部分你們能夠本身去摸索下,最後一項支持OQL(對象查詢語言)。
D、jstat(JVM統計監測工具)
語法格式以下:
1
|
<code class=
"hljs css"
><span class=
"hljs-selector-tag"
>jstat <span class=
"hljs-selector-attr"
>[ generalOption | outputOptions vmid [interval[s|ms] <span class=
"hljs-selector-attr"
>[count]] ]<
/span
><
/span
><
/span
><
/code
>
|
vmid是Java虛擬機ID,在Linux/Unix系統上通常就是進程ID。interval是採樣時間間隔。count是採樣數目。好比下面輸出的是GC信息,採樣時間間隔爲250ms,採樣數爲4:
1
2
3
4
5
6
|
<code class=
"hljs less"
>root<span class=
"hljs-variable"
>@ubuntu:/
# jstat -gc <span class="hljs-number">21711 <span class="hljs-number">250 <span class="hljs-number">4
S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT
<span class=
"hljs-number"
>192.0 <span class=
"hljs-number"
>192.0 <span class=
"hljs-number"
>64.0 <span class=
"hljs-number"
>0.0 <span class=
"hljs-number"
>6144.0 <span class=
"hljs-number"
>1854.9 <span class=
"hljs-number"
>32000.0 <span class=
"hljs-number"
>4111.6 <span class=
"hljs-number"
>55296.0 <span class=
"hljs-number"
>25472.7 <span class=
"hljs-number"
>702 <span class=
"hljs-number"
>0.431 <span class=
"hljs-number"
>3 <span class=
"hljs-number"
>0.218 <span class=
"hljs-number"
>0.649
<span class=
"hljs-number"
>192.0 <span class=
"hljs-number"
>192.0 <span class=
"hljs-number"
>64.0 <span class=
"hljs-number"
>0.0 <span class=
"hljs-number"
>6144.0 <span class=
"hljs-number"
>1972.2 <span class=
"hljs-number"
>32000.0 <span class=
"hljs-number"
>4111.6 <span class=
"hljs-number"
>55296.0 <span class=
"hljs-number"
>25472.7 <span class=
"hljs-number"
>702 <span class=
"hljs-number"
>0.431 <span class=
"hljs-number"
>3 <span class=
"hljs-number"
>0.218 <span class=
"hljs-number"
>0.649
<span class=
"hljs-number"
>192.0 <span class=
"hljs-number"
>192.0 <span class=
"hljs-number"
>64.0 <span class=
"hljs-number"
>0.0 <span class=
"hljs-number"
>6144.0 <span class=
"hljs-number"
>1972.2 <span class=
"hljs-number"
>32000.0 <span class=
"hljs-number"
>4111.6 <span class=
"hljs-number"
>55296.0 <span class=
"hljs-number"
>25472.7 <span class=
"hljs-number"
>702 <span class=
"hljs-number"
>0.431 <span class=
"hljs-number"
>3 <span class=
"hljs-number"
>0.218 <span class=
"hljs-number"
>0.649
<span class=
"hljs-number"
>192.0 <span class=
"hljs-number"
>192.0 <span class=
"hljs-number"
>64.0 <span class=
"hljs-number"
>0.0 <span class=
"hljs-number"
>6144.0 <span class=
"hljs-number"
>2109.7 <span class=
"hljs-number"
>32000.0 <span class=
"hljs-number"
>4111.6 <span class=
"hljs-number"
>55296.0 <span class=
"hljs-number"
>25472.7 <span class=
"hljs-number"
>702 <span class=
"hljs-number"
>0.431 <span class=
"hljs-number"
>3 <span class=
"hljs-number"
>0.218 <span class=
"hljs-number"
>0.649<
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/code
>
|
要明白上面各列的意義,先看JVM堆內存佈局:
能夠看出:
1
2
|
<code class=
"hljs gradle"
>堆內存 = 年輕代 + 年老代 + 永久代
年輕代 = Eden區 + 兩個Survivor區(<span class=
"hljs-keyword"
>From和To)<
/span
><
/code
>
|
如今來解釋各列含義:
1
2
3
4
5
6
7
|
<code class=
"hljs"
>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總耗時<
/code
>
|
E、hprof(Heap/CPU Profiling Tool)
hprof可以展示CPU使用率,統計堆內存使用狀況。
語法格式以下:
1
2
3
|
<code class=
"hljs css"
><span class=
"hljs-selector-tag"
>java <span class=
"hljs-selector-tag"
>-agentlib<span class=
"hljs-selector-pseudo"
>:hprof<span class=
"hljs-selector-attr"
>[=options] <span class=
"hljs-selector-tag"
>ToBeProfiledClass
<span class=
"hljs-selector-tag"
>java <span class=
"hljs-selector-tag"
>-Xrunprof<span class=
"hljs-selector-attr"
>[:options] <span class=
"hljs-selector-tag"
>ToBeProfiledClass
<span class=
"hljs-selector-tag"
>javac <span class=
"hljs-selector-tag"
>-J-agentlib<span class=
"hljs-selector-pseudo"
>:hprof<span class=
"hljs-selector-attr"
>[=options] <span class=
"hljs-selector-tag"
>ToBeProfiledClass<
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/span
><
/code
>
|
完整的命令選項以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<code class=
"hljs makefile"
>Option Name and Value Description Default
--------------------- ----------- -------
heap=dump|sites|all heap profiling all
cpu=samples|
times
|old CPU usage off
monitor=y|n monitor contention n
format
=a|b text(txt) or binary output a
file
=<
file
> write data to
file
java.hprof[.txt]
net=<host>:<port> send data over a socket off
depth=<size> stack trace depth 4
interval=<ms> sample interval
in
ms 10
cutoff=<value> output cutoff point 0.0001
lineno=y|n line number
in
traces? y
thread=y|n thread
in
traces? n
doe=y|n dump on
exit
? y
msa=y|n Solaris micro state accounting n
force=y|n force output to <
file
> y
verbose=y|n print messages about dumps y<
/code
>
|
來幾個官方指南上的實例。
CPU Usage Sampling Profiling(cpu=samples)的例子:
1
|
<code class=
"hljs nginx"
><span class=
"hljs-attribute"
>java -agentlib:hprof=cpu=samples,interval=<span class=
"hljs-number"
>20,depth=<span class=
"hljs-number"
>3 Hello<
/span
><
/span
><
/span
><
/code
>
|
上面每隔20毫秒採樣CPU消耗信息,堆棧深度爲3,生成的profile文件名稱是java.hprof.txt,在當前目錄。
CPU Usage Times Profiling(cpu=times)的例子,它相對於CPU Usage Sampling Profile可以得到更加細粒度的CPU消耗信息,可以細到每一個方法調用的開始和結束,它的實現使用了字節碼注入技術(BCI):
1
|
<code class=
"hljs bash"
>javac -J-agentlib:hprof=cpu=<span class=
"hljs-built_in"
>
times
Hello.java<
/span
><
/code
>
|
Heap Allocation Profiling(heap=sites)的例子:
1
|
<code class=
"hljs nginx"
><span class=
"hljs-attribute"
>javac -J-agentlib:hprof=heap=sites Hello.java<
/span
><
/code
>
|
Heap Dump(heap=dump)的例子,它比上面的Heap Allocation Profiling能生成更詳細的Heap Dump信息:
1
|
<code class=
"hljs nginx"
><span class=
"hljs-attribute"
>javac -J-agentlib:hprof=heap=dump Hello.java<
/span
><
/code
>
|
雖然在JVM啓動參數中加入-Xrunprof:heap=sites參數能夠生成CPU/Heap Profile文件,但對JVM性能影響很是大,不建議在線上服務器環境使用。
其餘JVM性能調優參考資料:
《Java虛擬機規範》
《Java Performance》
《Trouble Shooting Guide for JavaSE 6 with HotSpot VM》: http://www.oracle.com/technetwork/java/javase/tsg-vm-149989.pdf
《Effective Java》
VisualVM: http://docs.oracle.com/javase/7/docs/technotes/guides/visualvm/
jConsole: http://docs.oracle.com/javase/1.5.0/docs/guide/management/jconsole.html
Monitoring and Managing JavaSE 6 Applications: http://www.oracle.com/technetwork/articles/javase/monitoring-141801.html