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

 

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