JVM性能调优监控工具

原文链接:https://www.cnblogs.com/haiyang1985/p/7654654.html

JVM性能调优监控工具

摘要: JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps、jstack、jmap、jhat、jstat、hprof等小巧的工具,本博客希望能起抛砖引玉之用,让大家能开始对JVM性能调优的常用工具有所了解。

    现实企业级Java开发中,有时候我们会碰到下面这些问题:

  • OutOfMemoryError,内存不足

  • 内存泄露

  • 线程死锁

  • 锁争用(Lock Contention)

  • Java进程消耗CPU过高

  • ......

    这些问题在日常开发中可能被很多人忽视(比如有的人遇到上面的问题只是重启服务器或者调大内存,而不会深究问题根源),但能够理解并解决这些问题是Java程序员进阶的必备要求。本文将对一些常用的JVM性能调优监控工具进行介绍,希望能起抛砖引玉之用。本文参考了网上很多资料,难以一一列举,在此对这些资料的作者表示感谢!关于JVM性能调优相关的资料,请参考文末。

 

A、 jps(Java Virtual Machine Process Status Tool)      

    jps主要用来输出JVM中运行的进程状态信息。语法格式如下:

?

1

<code class="hljs css"><span class="hljs-selector-tag"><span class="hljs-selector-tag">jps</span> <span class="hljs-selector-attr"><span class="hljs-selector-attr">[options]</span> <span class="hljs-selector-attr"><span class="hljs-selector-attr">[hostid]</span></span></span></span></code>

    如果不指定hostid就默认为当前主机或服务器。

    命令行参数选项说明如下:

?

1

2

3

4

<code class="hljs haml diff"><span class="hljs-deletion">-</span><span class="ruby"><span class="hljs-deletion">q 不输出类名、Jar名和传入main方法的参数</span>

<span class="hljs-deletion">-</span><span class="ruby"><span class="hljs-deletion">m 输出传入main方法的参数</span>

<span class="hljs-deletion">-</span><span class="ruby"><span class="hljs-deletion">l 输出main类或Jar的全限名</span>

<span class="hljs-deletion">-</span><span class="ruby"><span class="hljs-deletion">v 输出传入JVM的参数</span></span></span></span></span></code>

   比如下面:

?

1

2

3

4

5

6

7

8

<code class="hljs less"><span class="hljs-selector-tag">root</span><span class="hljs-variable">@<span class="hljs-selector-tag">ubuntu</span>:/# <span class="hljs-selector-tag">jps</span> <span class="hljs-selector-tag">-m</span> <span class="hljs-selector-tag">-l</span>

<span class="hljs-number"><span class="hljs-selector-tag">2458</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.artifactory</span><span class="hljs-selector-class">.standalone</span><span class="hljs-selector-class">.main</span><span class="hljs-selector-class">.Main</span> /<span class="hljs-selector-tag">usr</span>/<span class="hljs-selector-tag">local</span>/<span class="hljs-selector-tag">artifactory-</span><span class="hljs-number"><span class="hljs-selector-tag">2</span><span class="hljs-selector-class">.2</span><span class="hljs-selector-class">.</span><span class="hljs-number"><span class="hljs-selector-class">5</span>/<span class="hljs-selector-tag">etc</span>/<span class="hljs-selector-tag">jetty</span><span class="hljs-selector-class">.xml</span>

<span class="hljs-number"><span class="hljs-selector-tag">29920</span> <span class="hljs-selector-tag">com</span><span class="hljs-selector-class">.sun</span><span class="hljs-selector-class">.tools</span><span class="hljs-selector-class">.hat</span><span class="hljs-selector-class">.Main</span> <span class="hljs-selector-tag">-port</span> <span class="hljs-number"><span class="hljs-selector-tag">9998</span> /<span class="hljs-selector-tag">tmp</span>/<span class="hljs-selector-tag">dump</span><span class="hljs-selector-class">.dat</span>

<span class="hljs-number"><span class="hljs-selector-tag">3149</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.apache</span><span class="hljs-selector-class">.catalina</span><span class="hljs-selector-class">.startup</span><span class="hljs-selector-class">.Bootstrap</span> <span class="hljs-selector-tag">start</span>

<span class="hljs-number"><span class="hljs-selector-tag">30972</span> <span class="hljs-selector-tag">sun</span><span class="hljs-selector-class">.tools</span><span class="hljs-selector-class">.jps</span><span class="hljs-selector-class">.Jps</span> <span class="hljs-selector-tag">-m</span> <span class="hljs-selector-tag">-l</span>

<span class="hljs-number"><span class="hljs-selector-tag">8247</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.apache</span><span class="hljs-selector-class">.catalina</span><span class="hljs-selector-class">.startup</span><span class="hljs-selector-class">.Bootstrap</span> <span class="hljs-selector-tag">start</span>

<span class="hljs-number"><span class="hljs-selector-tag">25687</span> <span class="hljs-selector-tag">com</span><span class="hljs-selector-class">.sun</span><span class="hljs-selector-class">.tools</span><span class="hljs-selector-class">.hat</span><span class="hljs-selector-class">.Main</span> <span class="hljs-selector-tag">-port</span> <span class="hljs-number"><span class="hljs-selector-tag">9999</span> <span class="hljs-selector-tag">dump</span><span class="hljs-selector-class">.dat</span>

<span class="hljs-number"><span class="hljs-selector-tag">21711</span> <span class="hljs-selector-tag">mrf-center</span><span class="hljs-selector-class">.jar</span></span></span></span></span></span></span></span></span></span></span></span></span></code>

 

B、 jstack

    jstack主要用来查看某个Java进程内的线程堆栈信息。语法格式如下:

?

1

2

3

<code class="hljs css"><span class="hljs-selector-tag"><span class="hljs-selector-tag">jstack</span> <span class="hljs-selector-attr"><span class="hljs-selector-attr">[option]</span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">pid</span>

<span class="hljs-selector-tag"><span class="hljs-selector-tag">jstack</span> <span class="hljs-selector-attr"><span class="hljs-selector-attr">[option]</span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">executable</span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">core</span>

<span class="hljs-selector-tag"><span class="hljs-selector-tag">jstack</span> <span class="hljs-selector-attr"><span class="hljs-selector-attr">[option]</span> <span class="hljs-selector-attr"><span class="hljs-selector-attr">[server-id@]</span><span class="hljs-selector-tag"><span class="hljs-selector-tag">remote-hostname-or-ip</span></span></span></span></span></span></span></span></span></span></span></span></code>

    命令行参数选项说明如下:

?

1

2

<code class="hljs haml diff"><span class="hljs-deletion">-</span><span class="ruby"><span class="hljs-deletion">l long listings,会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁持有情况</span>

<span class="hljs-deletion">-</span><span class="ruby"><span class="hljs-deletion">m mixed mode,不仅会输出Java堆栈信息,还会输出C/C++堆栈信息(比如Native方法)</span></span></span></code>

    jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,所以它在JVM性能调优中使用得非常多。下面我们来一个实例找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息,用到的命令有ps、top、printf、jstack、grep。

    第一步先找出Java进程ID,我部署在服务器上的Java应用名称为mrf-center:

?

1

2

<code class="hljs less"><span class="hljs-selector-tag">root</span><span class="hljs-variable">@<span class="hljs-selector-tag">ubuntu</span>:/# <span class="hljs-selector-tag">ps</span> <span class="hljs-selector-tag">-ef</span> | <span class="hljs-selector-tag">grep</span> <span class="hljs-selector-tag">mrf-center</span> | <span class="hljs-selector-tag">grep</span> <span class="hljs-selector-tag">-v</span> <span class="hljs-selector-tag">grep</span>

<span class="hljs-selector-tag">root</span>     <span class="hljs-number"><span class="hljs-selector-tag">21711</span>     <span class="hljs-number"><span class="hljs-selector-tag">1</span>  <span class="hljs-number"><span class="hljs-selector-tag">1</span> <span class="hljs-number"><span class="hljs-selector-tag">14</span><span class="hljs-selector-pseudo">:</span><span class="hljs-number"><span class="hljs-selector-pseudo">47</span> <span class="hljs-selector-tag">pts</span>/<span class="hljs-number"><span class="hljs-selector-tag">3</span>    <span class="hljs-number"><span class="hljs-selector-tag">00</span><span class="hljs-selector-pseudo">:</span><span class="hljs-number"><span class="hljs-selector-pseudo">02</span><span class="hljs-selector-pseudo">:</span><span class="hljs-number"><span class="hljs-selector-pseudo">10</span> <span class="hljs-selector-tag">java</span> <span class="hljs-selector-tag">-jar</span> <span class="hljs-selector-tag">mrf-center</span><span class="hljs-selector-class">.jar</span></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"><span class="hljs-keyword">printf</span> <span class="hljs-string"><span class="hljs-string">"%x\n"</span> <span class="hljs-number"><span class="hljs-number">21742</span></span></span></span></code>

    得到21742的十六进制值为54ee,下面会用到。    

    OK,下一步终于轮到jstack上场了,它用来输出进程21711的堆栈信息,然后根据线程ID的十六进制值grep,如下:

?

1

2

<code class="hljs less"><span class="hljs-selector-tag">root</span><span class="hljs-variable">@<span class="hljs-selector-tag">ubuntu</span>:/# <span class="hljs-selector-tag">jstack</span> <span class="hljs-number"><span class="hljs-selector-tag">21711</span> | <span class="hljs-selector-tag">grep</span> <span class="hljs-number"><span class="hljs-selector-tag">54ee</span>

<span class="hljs-string">"<span class="hljs-selector-tag">PollIntervalRetrySchedulerThread</span>" <span class="hljs-selector-tag">prio</span>=<span class="hljs-number"><span class="hljs-selector-tag">10</span> <span class="hljs-selector-tag">tid</span>=<span class="hljs-number"><span class="hljs-selector-tag">0x00007f950043e000</span> <span class="hljs-selector-tag">nid</span>=<span class="hljs-number"><span class="hljs-selector-tag">0x54ee</span> <span class="hljs-selector-tag">in</span> <span class="hljs-selector-tag">Object</span><span class="hljs-selector-class">.wait</span>() <span class="hljs-selector-attr">[</span><span class="hljs-number"><span class="hljs-selector-attr">0x00007f94c6eda000]</span></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"><span class="hljs-comment">// Idle wait</span>

getLog().info(<span class="hljs-string"><span class="hljs-string">"Thread ["</span> + getName() + <span class="hljs-string"><span class="hljs-string">"] is idle waiting..."</span>);

schedulerThreadState = PollTaskSchedulerThreadState.IdleWaiting;

<span class="hljs-keyword"><span class="hljs-keyword">long</span> now = System.currentTimeMillis();

<span class="hljs-keyword"><span class="hljs-keyword">long</span> waitTime = now + getIdleWaitTime();

<span class="hljs-keyword"><span class="hljs-keyword">long</span> timeUntilContinue = waitTime - now;

<span class="hljs-keyword"><span class="hljs-keyword">synchronized</span>(sigLock) {

    <span class="hljs-keyword"><span class="hljs-keyword">try</span> {

        <span class="hljs-keyword"><span class="hljs-keyword">if</span>(!halted.get()) {

            sigLock.wait(timeUntilContinue);

        }

    

    <span class="hljs-keyword"><span class="hljs-keyword">catch</span> (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"><span class="hljs-selector-tag">jmap</span> <span class="hljs-selector-attr"><span class="hljs-selector-attr">[option]</span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">pid</span>

<span class="hljs-selector-tag"><span class="hljs-selector-tag">jmap</span> <span class="hljs-selector-attr"><span class="hljs-selector-attr">[option]</span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">executable</span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">core</span>

<span class="hljs-selector-tag"><span class="hljs-selector-tag">jmap</span> <span class="hljs-selector-attr"><span class="hljs-selector-attr">[option]</span> <span class="hljs-selector-attr"><span class="hljs-selector-attr">[server-id@]</span><span class="hljs-selector-tag"><span class="hljs-selector-tag">remote-hostname-or-ip</span></span></span></span></span></span></span></span></span></span></span></span></code>

    如果运行在64位JVM上,可能需要指定-J-d64命令选项参数。

?

1

<code class="hljs tcl nginx"><span class="hljs-attribute">jmap</span> -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"><span class="hljs-selector-tag">root</span><span class="hljs-variable">@<span class="hljs-selector-tag">ubuntu</span>:/# <span class="hljs-selector-tag">jmap</span> <span class="hljs-selector-tag">-heap</span> <span class="hljs-number"><span class="hljs-selector-tag">21711</span>

<span class="hljs-selector-tag">Attaching</span> <span class="hljs-selector-tag">to</span> <span class="hljs-selector-tag">process</span> <span class="hljs-selector-tag">ID</span> <span class="hljs-number"><span class="hljs-selector-tag">21711</span>, <span class="hljs-selector-tag">please</span> <span class="hljs-selector-tag">wait</span>...

<span class="hljs-selector-tag">Debugger</span> <span class="hljs-selector-tag">attached</span> <span class="hljs-selector-tag">successfully</span>.

<span class="hljs-selector-tag">Server</span> <span class="hljs-selector-tag">compiler</span> <span class="hljs-selector-tag">detected</span>.

<span class="hljs-selector-tag">JVM</span> <span class="hljs-selector-tag">version</span> <span class="hljs-selector-tag">is</span> <span class="hljs-number"><span class="hljs-selector-tag">20</span><span class="hljs-selector-class">.10-b01</span>

 

<span class="hljs-selector-tag">using</span> <span class="hljs-selector-tag">thread-local</span> <span class="hljs-selector-tag">object</span> <span class="hljs-selector-tag">allocation</span>.

<span class="hljs-selector-tag">Parallel</span> <span class="hljs-selector-tag">GC</span> <span class="hljs-selector-tag">with</span> <span class="hljs-number"><span class="hljs-selector-tag">4</span> <span class="hljs-selector-tag">thread</span>(s)

 

<span class="hljs-selector-tag">Heap</span> <span class="hljs-attribute"><span class="hljs-selector-tag">Configuration</span>:

   <span class="hljs-selector-tag">MinHeapFreeRatio</span> = <span class="hljs-number"><span class="hljs-selector-tag">40</span>

   <span class="hljs-selector-tag">MaxHeapFreeRatio</span> = <span class="hljs-number"><span class="hljs-selector-tag">70</span>

   <span class="hljs-selector-tag">MaxHeapSize</span>      = <span class="hljs-number"><span class="hljs-selector-tag">2067791872</span> (<span class="hljs-number"><span class="hljs-number">1972.0</span>MB)

   <span class="hljs-selector-tag">NewSize</span>          = <span class="hljs-number"><span class="hljs-selector-tag">1310720</span> (<span class="hljs-number"><span class="hljs-number">1.25</span>MB)

   <span class="hljs-selector-tag">MaxNewSize</span>       = <span class="hljs-number"><span class="hljs-selector-tag">17592186044415</span> <span class="hljs-selector-tag">MB</span>

   <span class="hljs-selector-tag">OldSize</span>          = <span class="hljs-number"><span class="hljs-selector-tag">5439488</span> (<span class="hljs-number"><span class="hljs-number">5.1875</span>MB)

   <span class="hljs-selector-tag">NewRatio</span>         = <span class="hljs-number"><span class="hljs-selector-tag">2</span>

   <span class="hljs-selector-tag">SurvivorRatio</span>    = <span class="hljs-number"><span class="hljs-selector-tag">8</span>

   <span class="hljs-selector-tag">PermSize</span>         = <span class="hljs-number"><span class="hljs-selector-tag">21757952</span> (<span class="hljs-number"><span class="hljs-number">20.75</span>MB)

   <span class="hljs-selector-tag">MaxPermSize</span>      = <span class="hljs-number"><span class="hljs-selector-tag">85983232</span> (<span class="hljs-number"><span class="hljs-number">82.0</span>MB)

 

<span class="hljs-selector-tag">Heap</span> <span class="hljs-attribute"><span class="hljs-selector-tag">Usage</span>:

<span class="hljs-selector-tag">PS</span> <span class="hljs-selector-tag">Young</span> <span class="hljs-selector-tag">Generation</span>

<span class="hljs-selector-tag">Eden</span> <span class="hljs-attribute"><span class="hljs-selector-tag">Space</span>:

   <span class="hljs-selector-tag">capacity</span> = <span class="hljs-number"><span class="hljs-selector-tag">6422528</span> (<span class="hljs-number"><span class="hljs-number">6.125</span>MB)

   <span class="hljs-selector-tag">used</span>     = <span class="hljs-number"><span class="hljs-selector-tag">5445552</span> (<span class="hljs-number"><span class="hljs-number">5.1932830810546875</span>MB)

   <span class="hljs-selector-tag">free</span>     = <span class="hljs-number"><span class="hljs-selector-tag">976976</span> (<span class="hljs-number"><span class="hljs-number">0.9317169189453125</span>MB)

   <span class="hljs-number"><span class="hljs-selector-tag">84</span><span class="hljs-selector-class">.78829520089286</span>% <span class="hljs-selector-tag">used</span>

<span class="hljs-selector-tag">From</span> <span class="hljs-attribute"><span class="hljs-selector-tag">Space</span>:

   <span class="hljs-selector-tag">capacity</span> = <span class="hljs-number"><span class="hljs-selector-tag">131072</span> (<span class="hljs-number"><span class="hljs-number">0.125</span>MB)

   <span class="hljs-selector-tag">used</span>     = <span class="hljs-number"><span class="hljs-selector-tag">98304</span> (<span class="hljs-number"><span class="hljs-number">0.09375</span>MB)

   <span class="hljs-selector-tag">free</span>     = <span class="hljs-number"><span class="hljs-selector-tag">32768</span> (<span class="hljs-number"><span class="hljs-number">0.03125</span>MB)

   <span class="hljs-number"><span class="hljs-selector-tag">75</span><span class="hljs-selector-class">.0</span>% <span class="hljs-selector-tag">used</span>

<span class="hljs-selector-tag">To</span> <span class="hljs-attribute"><span class="hljs-selector-tag">Space</span>:

   <span class="hljs-selector-tag">capacity</span> = <span class="hljs-number"><span class="hljs-selector-tag">131072</span> (<span class="hljs-number"><span class="hljs-number">0.125</span>MB)

   <span class="hljs-selector-tag">used</span>     = <span class="hljs-number"><span class="hljs-selector-tag">0</span> (<span class="hljs-number"><span class="hljs-number">0.0</span>MB)

   <span class="hljs-selector-tag">free</span>     = <span class="hljs-number"><span class="hljs-selector-tag">131072</span> (<span class="hljs-number"><span class="hljs-number">0.125</span>MB)

   <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.0</span>% <span class="hljs-selector-tag">used</span>

<span class="hljs-selector-tag">PS</span> <span class="hljs-selector-tag">Old</span> <span class="hljs-selector-tag">Generation</span>

   <span class="hljs-selector-tag">capacity</span> = <span class="hljs-number"><span class="hljs-selector-tag">35258368</span> (<span class="hljs-number"><span class="hljs-number">33.625</span>MB)

   <span class="hljs-selector-tag">used</span>     = <span class="hljs-number"><span class="hljs-selector-tag">4119544</span> (<span class="hljs-number"><span class="hljs-number">3.9287033081054688</span>MB)

   <span class="hljs-selector-tag">free</span>     = <span class="hljs-number"><span class="hljs-selector-tag">31138824</span> (<span class="hljs-number"><span class="hljs-number">29.69629669189453</span>MB)

   <span class="hljs-number"><span class="hljs-selector-tag">11</span><span class="hljs-selector-class">.683876009235595</span>% <span class="hljs-selector-tag">used</span>

<span class="hljs-selector-tag">PS</span> <span class="hljs-selector-tag">Perm</span> <span class="hljs-selector-tag">Generation</span>

   <span class="hljs-selector-tag">capacity</span> = <span class="hljs-number"><span class="hljs-selector-tag">52428800</span> (<span class="hljs-number"><span class="hljs-number">50.0</span>MB)

   <span class="hljs-selector-tag">used</span>     = <span class="hljs-number"><span class="hljs-selector-tag">26075168</span> (<span class="hljs-number"><span class="hljs-number">24.867218017578125</span>MB)

   <span class="hljs-selector-tag">free</span>     = <span class="hljs-number"><span class="hljs-selector-tag">26353632</span> (<span class="hljs-number"><span class="hljs-number">25.132781982421875</span>MB)

   <span class="hljs-number"><span class="hljs-selector-tag">49</span><span class="hljs-selector-class">.73443603515625</span>% <span class="hljs-selector-tag">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></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"><span class="hljs-number">#b</span>ytes  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"><span class="hljs-variable">$Entry</span>

  18:          1869         138568  [Ljava.util.HashMap<span class="hljs-variable"><span class="hljs-variable">$Entry</span>;

  19:          <span class="hljs-number"><span class="hljs-number">2443</span>          <span class="hljs-number"><span class="hljs-number">97720</span>  java.util.LinkedHashMap<span class="hljs-variable"><span class="hljs-variable">$Entry</span>

  <span class="hljs-number"><span class="hljs-number">20</span>:          <span class="hljs-number"><span class="hljs-number">2072</span>          <span class="hljs-number"><span class="hljs-number">82880</span>  java.lang.ref.SoftReference

  <span class="hljs-number"><span class="hljs-number">21</span>:          <span class="hljs-number"><span class="hljs-number">1807</span>          <span class="hljs-number"><span class="hljs-number">71528</span>  [Ljava.lang.Object;

  22:          <span class="hljs-number"><span class="hljs-number">2206</span>          <span class="hljs-number"><span class="hljs-number">70592</span>  java.lang.ref.WeakReference

  <span class="hljs-number"><span class="hljs-number">23</span>:           <span class="hljs-number"><span class="hljs-number">934</span>          <span class="hljs-number"><span class="hljs-number">52304</span>  java.util.LinkedHashMap

  <span class="hljs-number"><span class="hljs-number">24</span>:           <span class="hljs-number"><span class="hljs-number">871</span>          <span class="hljs-number"><span class="hljs-number">48776</span>  java.beans.MethodDescriptor

  <span class="hljs-number"><span class="hljs-number">25</span>:          <span class="hljs-number"><span class="hljs-number">1442</span>          <span class="hljs-number"><span class="hljs-number">46144</span>  java.util.concurrent.ConcurrentHashMap<span class="hljs-variable"><span class="hljs-variable">$HashEntry</span>

  <span class="hljs-number"><span class="hljs-number">26</span>:           <span class="hljs-number"><span class="hljs-number">804</span>          <span class="hljs-number"><span class="hljs-number">38592</span>  java.util.HashMap

  <span class="hljs-number"><span class="hljs-number">27</span>:           <span class="hljs-number"><span class="hljs-number">948</span>          <span class="hljs-number"><span class="hljs-number">37920</span>  java.util.concurrent.ConcurrentHashMap<span class="hljs-variable"><span class="hljs-variable">$Segment</span>

  <span class="hljs-number"><span class="hljs-number">28</span>:          <span class="hljs-number"><span class="hljs-number">1621</span>          <span class="hljs-number"><span class="hljs-number">35696</span>  [Ljava.lang.Class;

  29:          <span class="hljs-number"><span class="hljs-number">1313</span>          <span class="hljs-number"><span class="hljs-number">34880</span>  [Ljava.lang.String;

  30:          <span class="hljs-number"><span class="hljs-number">1396</span>          <span class="hljs-number"><span class="hljs-number">33504</span>  java.util.LinkedList<span class="hljs-variable"><span class="hljs-variable">$Entry</span>

  <span class="hljs-number"><span class="hljs-number">31</span>:           <span class="hljs-number"><span class="hljs-number">462</span>          <span class="hljs-number"><span class="hljs-number">33264</span>  java.lang.reflect.Field

  <span class="hljs-number"><span class="hljs-number">32</span>:          <span class="hljs-number"><span class="hljs-number">1024</span>          <span class="hljs-number"><span class="hljs-number">32768</span>  java.util.Hashtable<span class="hljs-variable"><span class="hljs-variable">$Entry</span>

  <span class="hljs-number"><span class="hljs-number">33</span>:           <span class="hljs-number"><span class="hljs-number">948</span>          <span class="hljs-number"><span class="hljs-number">31440</span>  [Ljava.util.concurrent.ConcurrentHashMap<span class="hljs-variable"><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></span></code>

    class name是对象类型,说明如下:

?

1

2

3

4

5

6

7

8

9

<code class="hljs java">B  <span class="hljs-keyword"><span class="hljs-keyword">byte</span>

C  <span class="hljs-keyword"><span class="hljs-keyword">char</span>

D  <span class="hljs-keyword"><span class="hljs-keyword">double</span>

F  <span class="hljs-keyword"><span class="hljs-keyword">float</span>

I  <span class="hljs-keyword"><span class="hljs-keyword">int</span>

J  <span class="hljs-keyword"><span class="hljs-keyword">long</span>

Z  <span class="hljs-keyword"><span class="hljs-keyword">boolean</span>

[  数组,如[I表示<span class="hljs-keyword"><span class="hljs-keyword">int</span>[]

[L+类名 其他对象</span></span></span></span></span></span></span></span></code>

    还有一个很常用的情况是:用jmap把进程内存使用情况dump到文件中,再用jhat分析查看。jmap进行dump命令格式如下:

?

1

<code class="hljs tcl lua">jmap -<span class="hljs-built_in">dump</span>:<span class="hljs-keyword"><span class="hljs-built_in">format</span>=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"><span class="hljs-selector-tag">root</span><span class="hljs-variable">@<span class="hljs-selector-tag">ubuntu</span>:/# <span class="hljs-selector-tag">jmap</span> <span class="hljs-attribute"><span class="hljs-selector-tag">-dump</span><span class="hljs-selector-pseudo">:format</span>=<span class="hljs-selector-tag">b</span>,<span class="hljs-selector-tag">file</span>=/<span class="hljs-selector-tag">tmp</span>/<span class="hljs-selector-tag">dump</span><span class="hljs-selector-class">.dat</span> <span class="hljs-number"><span class="hljs-selector-tag">21711</span>     

<span class="hljs-selector-tag">Dumping</span> <span class="hljs-selector-tag">heap</span> <span class="hljs-selector-tag">to</span> /<span class="hljs-selector-tag">tmp</span>/<span class="hljs-selector-tag">dump</span><span class="hljs-selector-class">.dat</span> ...

<span class="hljs-selector-tag">Heap</span> <span class="hljs-selector-tag">dump</span> <span class="hljs-selector-tag">file</span> <span class="hljs-selector-tag">created</span></span></span></span></code>

   dump出来的文件可以用MAT、VisualVM等工具查看,这里用jhat查看:

?

1

2

3

4

5

6

7

8

9

10

<code class="hljs less"><span class="hljs-selector-tag">root</span><span class="hljs-variable">@<span class="hljs-selector-tag">ubuntu</span>:/# <span class="hljs-selector-tag">jhat</span> <span class="hljs-selector-tag">-port</span> <span class="hljs-number"><span class="hljs-selector-tag">9998</span> /<span class="hljs-selector-tag">tmp</span>/<span class="hljs-selector-tag">dump</span><span class="hljs-selector-class">.dat</span>

<span class="hljs-selector-tag">Reading</span> <span class="hljs-selector-tag">from</span> /<span class="hljs-selector-tag">tmp</span>/<span class="hljs-selector-tag">dump</span><span class="hljs-selector-class">.dat</span>...

<span class="hljs-selector-tag">Dump</span> <span class="hljs-selector-tag">file</span> <span class="hljs-selector-tag">created</span> <span class="hljs-selector-tag">Tue</span> <span class="hljs-selector-tag">Jan</span> <span class="hljs-number"><span class="hljs-selector-tag">28</span> <span class="hljs-number"><span class="hljs-selector-tag">17</span><span class="hljs-selector-pseudo">:</span><span class="hljs-number"><span class="hljs-selector-pseudo">46</span><span class="hljs-selector-pseudo">:</span><span class="hljs-number"><span class="hljs-selector-pseudo">14</span> <span class="hljs-selector-tag">CST</span> <span class="hljs-number"><span class="hljs-selector-tag">2014</span>

<span class="hljs-selector-tag">Snapshot</span> <span class="hljs-selector-tag">read</span>, <span class="hljs-selector-tag">resolving</span>...

<span class="hljs-selector-tag">Resolving</span> <span class="hljs-number"><span class="hljs-selector-tag">132207</span> <span class="hljs-selector-tag">objects</span>...

<span class="hljs-selector-tag">Chasing</span> <span class="hljs-selector-tag">references</span>, <span class="hljs-selector-tag">expect</span> <span class="hljs-number"><span class="hljs-selector-tag">26</span> <span class="hljs-selector-tag">dots</span>..........................

<span class="hljs-selector-tag">Eliminating</span> <span class="hljs-selector-tag">duplicate</span> <span class="hljs-selector-tag">references</span>..........................

<span class="hljs-selector-tag">Snapshot</span> <span class="hljs-selector-tag">resolved</span>.

<span class="hljs-selector-tag">Started</span> <span class="hljs-selector-tag">HTTP</span> <span class="hljs-selector-tag">server</span> <span class="hljs-selector-tag">on</span> <span class="hljs-selector-tag">port</span> <span class="hljs-number"><span class="hljs-selector-tag">9998</span>

<span class="hljs-selector-tag">Server</span> <span class="hljs-selector-tag">is</span> <span class="hljs-selector-tag">ready</span>.</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"><span class="hljs-selector-tag">jstat</span> <span class="hljs-selector-attr"><span class="hljs-selector-attr">[ generalOption | outputOptions vmid [interval[s|ms]</span> <span class="hljs-selector-attr"><span class="hljs-selector-attr">[count]</span>] ]</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"><span class="hljs-selector-tag">root</span><span class="hljs-variable">@<span class="hljs-selector-tag">ubuntu</span>:/# <span class="hljs-selector-tag">jstat</span> <span class="hljs-selector-tag">-gc</span> <span class="hljs-number"><span class="hljs-selector-tag">21711</span> <span class="hljs-number"><span class="hljs-selector-tag">250</span> <span class="hljs-number"><span class="hljs-selector-tag">4</span>

 <span class="hljs-selector-tag">S0C</span>    <span class="hljs-selector-tag">S1C</span>    <span class="hljs-selector-tag">S0U</span>    <span class="hljs-selector-tag">S1U</span>      <span class="hljs-selector-tag">EC</span>       <span class="hljs-selector-tag">EU</span>        <span class="hljs-selector-tag">OC</span>         <span class="hljs-selector-tag">OU</span>       <span class="hljs-selector-tag">PC</span>     <span class="hljs-selector-tag">PU</span>    <span class="hljs-selector-tag">YGC</span>     <span class="hljs-selector-tag">YGCT</span>    <span class="hljs-selector-tag">FGC</span>    <span class="hljs-selector-tag">FGCT</span>     <span class="hljs-selector-tag">GCT</span>   

<span class="hljs-number"><span class="hljs-selector-tag">192</span><span class="hljs-selector-class">.0</span>  <span class="hljs-number"><span class="hljs-selector-tag">192</span><span class="hljs-selector-class">.0</span>   <span class="hljs-number"><span class="hljs-selector-tag">64</span><span class="hljs-selector-class">.0</span>   <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.0</span>    <span class="hljs-number"><span class="hljs-selector-tag">6144</span><span class="hljs-selector-class">.0</span>   <span class="hljs-number"><span class="hljs-selector-tag">1854</span><span class="hljs-selector-class">.9</span>   <span class="hljs-number"><span class="hljs-selector-tag">32000</span><span class="hljs-selector-class">.0</span>     <span class="hljs-number"><span class="hljs-selector-tag">4111</span><span class="hljs-selector-class">.6</span>   <span class="hljs-number"><span class="hljs-selector-tag">55296</span><span class="hljs-selector-class">.0</span> <span class="hljs-number"><span class="hljs-selector-tag">25472</span><span class="hljs-selector-class">.7</span>    <span class="hljs-number"><span class="hljs-selector-tag">702</span>    <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.431</span>   <span class="hljs-number"><span class="hljs-selector-tag">3</span>      <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.218</span>    <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.649</span>

<span class="hljs-number"><span class="hljs-selector-tag">192</span><span class="hljs-selector-class">.0</span>  <span class="hljs-number"><span class="hljs-selector-tag">192</span><span class="hljs-selector-class">.0</span>   <span class="hljs-number"><span class="hljs-selector-tag">64</span><span class="hljs-selector-class">.0</span>   <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.0</span>    <span class="hljs-number"><span class="hljs-selector-tag">6144</span><span class="hljs-selector-class">.0</span>   <span class="hljs-number"><span class="hljs-selector-tag">1972</span><span class="hljs-selector-class">.2</span>   <span class="hljs-number"><span class="hljs-selector-tag">32000</span><span class="hljs-selector-class">.0</span>     <span class="hljs-number"><span class="hljs-selector-tag">4111</span><span class="hljs-selector-class">.6</span>   <span class="hljs-number"><span class="hljs-selector-tag">55296</span><span class="hljs-selector-class">.0</span> <span class="hljs-number"><span class="hljs-selector-tag">25472</span><span class="hljs-selector-class">.7</span>    <span class="hljs-number"><span class="hljs-selector-tag">702</span>    <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.431</span>   <span class="hljs-number"><span class="hljs-selector-tag">3</span>      <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.218</span>    <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.649</span>

<span class="hljs-number"><span class="hljs-selector-tag">192</span><span class="hljs-selector-class">.0</span>  <span class="hljs-number"><span class="hljs-selector-tag">192</span><span class="hljs-selector-class">.0</span>   <span class="hljs-number"><span class="hljs-selector-tag">64</span><span class="hljs-selector-class">.0</span>   <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.0</span>    <span class="hljs-number"><span class="hljs-selector-tag">6144</span><span class="hljs-selector-class">.0</span>   <span class="hljs-number"><span class="hljs-selector-tag">1972</span><span class="hljs-selector-class">.2</span>   <span class="hljs-number"><span class="hljs-selector-tag">32000</span><span class="hljs-selector-class">.0</span>     <span class="hljs-number"><span class="hljs-selector-tag">4111</span><span class="hljs-selector-class">.6</span>   <span class="hljs-number"><span class="hljs-selector-tag">55296</span><span class="hljs-selector-class">.0</span> <span class="hljs-number"><span class="hljs-selector-tag">25472</span><span class="hljs-selector-class">.7</span>    <span class="hljs-number"><span class="hljs-selector-tag">702</span>    <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.431</span>   <span class="hljs-number"><span class="hljs-selector-tag">3</span>      <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.218</span>    <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.649</span>

<span class="hljs-number"><span class="hljs-selector-tag">192</span><span class="hljs-selector-class">.0</span>  <span class="hljs-number"><span class="hljs-selector-tag">192</span><span class="hljs-selector-class">.0</span>   <span class="hljs-number"><span class="hljs-selector-tag">64</span><span class="hljs-selector-class">.0</span>   <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.0</span>    <span class="hljs-number"><span class="hljs-selector-tag">6144</span><span class="hljs-selector-class">.0</span>   <span class="hljs-number"><span class="hljs-selector-tag">2109</span><span class="hljs-selector-class">.7</span>   <span class="hljs-number"><span class="hljs-selector-tag">32000</span><span class="hljs-selector-class">.0</span>     <span class="hljs-number"><span class="hljs-selector-tag">4111</span><span class="hljs-selector-class">.6</span>   <span class="hljs-number"><span class="hljs-selector-tag">55296</span><span class="hljs-selector-class">.0</span> <span class="hljs-number"><span class="hljs-selector-tag">25472</span><span class="hljs-selector-class">.7</span>    <span class="hljs-number"><span class="hljs-selector-tag">702</span>    <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.431</span>   <span class="hljs-number"><span class="hljs-selector-tag">3</span>      <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.218</span>    <span class="hljs-number"><span class="hljs-selector-tag">0</span><span class="hljs-selector-class">.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></span></code>

    要明白上面各列的意义,先看JVM堆内存布局:

    可以看出:

?

1

2

<code class="hljs gradle vbnet">堆内存 = 年轻代 + 年老代 + 永久代

年轻代 = Eden区 + 两个Survivor区(<span class="hljs-keyword"><span class="hljs-keyword">From</span>和<span class="hljs-keyword">To</span>)</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"><span class="hljs-selector-tag">java</span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">-agentlib</span><span class="hljs-selector-pseudo"><span class="hljs-selector-pseudo">:hprof</span><span class="hljs-selector-attr"><span class="hljs-selector-attr">[=options]</span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">ToBeProfiledClass</span>

<span class="hljs-selector-tag"><span class="hljs-selector-tag">java</span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">-Xrunprof</span><span class="hljs-selector-attr"><span class="hljs-selector-attr">[:options]</span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">ToBeProfiledClass</span>

<span class="hljs-selector-tag"><span class="hljs-selector-tag">javac</span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">-J-agentlib</span><span class="hljs-selector-pseudo"><span class="hljs-selector-pseudo">:hprof</span><span class="hljs-selector-attr"><span class="hljs-selector-attr">[=options]</span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">ToBeProfiledClass</span></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"><span class="hljs-attribute">java</span> -agentlib:hprof=cpu=samples,interval=<span class="hljs-number"><span class="hljs-number">20</span>,depth=<span class="hljs-number"><span class="hljs-number">3</span> 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"><span class="hljs-built_in">times</span> Hello.java</span></code>

    Heap Allocation Profiling(heap=sites)的例子:

?

1

<code class="hljs nginx"><span class="hljs-attribute"><span class="hljs-attribute">javac</span> -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"><span class="hljs-attribute">javac</span> -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

BTrace:https://kenai.com/projects/btrace

 

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