这些问题在平常开发中可能被不少人忽视(好比有的人遇到上面的问题只是重启服务器或者调大内存,而不会深究问题根源),但可以理解并解决这些问题是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