1. 程式人生 > >Born To Learn And Share

Born To Learn And Share

    現實企業級Java開發中,有時候我們會碰到下面這些問題:

  • OutOfMemoryError,記憶體不足

  • 記憶體洩露

  • 執行緒死鎖

  • 鎖爭用(Lock Contention)

  • Java程序消耗CPU過高

  • ......

    這些問題在日常開發中可能被很多人忽視(比如有的人遇到上面的問題只是重啟伺服器或者調大記憶體,而不會深究問題根源),但能夠理解並解決這些問題是Java程式設計師進階的必備要求。本文將對一些常用的JVM效能調優監控工具進行介紹,希望能起拋磚引玉之用。本文參考了網上很多資料,難以一一列舉,在此對這些資料的作者表示感謝!關於JVM效能調優相關的資料,請參考文末。

A、

 jps(Java Virtual Machine Process Status Tool)      

    jps主要用來輸出JVM中執行的程序狀態資訊。語法格式如下:

jps [options] [hostid]

    如果不指定hostid就預設為當前主機或伺服器。

    命令列引數選項說明如下:

-q 不輸出類名、Jar名和傳入main方法的引數
-m 輸出傳入main方法的引數
-l 輸出main類或Jar的全限名
-v 輸出傳入JVM的引數

   比如下面:

[email protected]:/# jps -m -l2458 org.artifactory.standalone.main
.Main /usr/local/artifactory-2.2.5/etc/jetty.xml 29920 com.sun.tools.hat.Main -port 9998 /tmp/dump.dat 3149 org.apache.catalina.startup.Bootstrap start 30972 sun.tools.jps.Jps -m -l 8247 org.apache.catalina.startup.Bootstrap start 25687 com.sun.tools.hat.Main -port 9999 dump.dat 21711 mrf-center.jar

B、 jstack

    jstack主要用來檢視某個Java程序內的執行緒堆疊資訊。語法格式如下:

jstack [option] pid
jstack [option] executable core
jstack [option] [server[email protected]]remote-hostname-or-ip

    命令列引數選項說明如下:

-l long listings,會打印出額外的鎖資訊,在發生死鎖時可以用jstack -l pid來觀察鎖持有情況
-m mixed mode,不僅會輸出Java堆疊資訊,還會輸出C/C++堆疊資訊(比如Native方法)

    jstack可以定位到執行緒堆疊,根據堆疊資訊我們可以定位到具體程式碼,所以它在JVM效能調優中使用得非常多。下面我們來一個例項找出某個Java程序中最耗費CPU的Java執行緒並定位堆疊資訊,用到的命令有ps、top、printf、jstack、grep。

    第一步先找出Java程序ID,我部署在伺服器上的Java應用名稱為mrf-center:

root@ubuntu:/# ps -ef | grep mrf-center | grep -v grep
root     21711     1  1 14:47 pts/3    00:02:10 java -jar mrf-center.jar

    得到程序ID為21711,第二步找出該程序內最耗費CPU的執行緒,可以使用ps -Lfp pid或者ps -mp pid -o THREAD, tid, time或者top -Hp pid,我這裡用第三個,輸出如下:

    TIME列就是各個Java執行緒耗費的CPU時間,CPU時間最長的是執行緒ID為21742的執行緒,用

printf "%x\n" 21742

    得到21742的十六進位制值為54ee,下面會用到。    

    OK,下一步終於輪到jstack上場了,它用來輸出程序21711的堆疊資訊,然後根據執行緒ID的十六進位制值grep,如下:

[email protected]:/# jstack 21711 | grep 54ee"PollIntervalRetrySchedulerThread" prio=10 tid=0x00007f950043e000 nid=0x54ee in Object.wait() [0x00007f94c6eda000]

    可以看到CPU消耗在PollIntervalRetrySchedulerThread這個類的Object.wait(),我找了下我的程式碼,定位到下面的程式碼:

// Idle wait
getLog().info("Thread [" + getName() + "] is idle waiting...");
schedulerThreadState = PollTaskSchedulerThreadState.IdleWaiting;
long now = System.currentTimeMillis();
long waitTime = now + getIdleWaitTime();
long timeUntilContinue = waitTime - now;
synchronized(sigLock) {
    try {
    	if(!halted.get()) {
    		sigLock.wait(timeUntilContinue);
    	}
    } 
    catch (InterruptedException ignore) {
    }
}

    它是輪詢任務的空閒等待程式碼,上面的sigLock.wait(timeUntilContinue)就對應了前面的Object.wait()。

C、 jmap(Memory Map)和jhat(Java Heap Analysis Tool)

    jmap用來檢視堆記憶體使用狀況,一般結合jhat使用。

    jmap語法格式如下:

jmap [option] pid
jmap [option] executable core
jmap [option] [server[email protected]]remote-hostname-or-ip

    如果執行在64位JVM上,可能需要指定-J-d64命令選項引數。

jmap -permstat pid

    列印程序的類載入器和類載入器載入的持久代物件資訊,輸出:類載入器名稱、物件是否存活(不可靠)、物件地址、父類載入器、已載入的類大小等資訊,如下圖:

   使用jmap -heap pid檢視程序堆記憶體使用情況,包括使用的GC演算法、堆配置引數和各代中堆記憶體使用情況。比如下面的例子:

[email protected]:/# jmap -heap 21711
Attaching to process ID 21711, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 20.10-b01

using thread-local object allocation.
Parallel GC with 4 thread(s)

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 2067791872 (1972.0MB)
   NewSize          = 1310720 (1.25MB)
   MaxNewSize       = 17592186044415 MB
   OldSize          = 5439488 (5.1875MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 21757952 (20.75MB)
   MaxPermSize      = 85983232 (82.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 6422528 (6.125MB)
   used     = 5445552 (5.1932830810546875MB)
   free     = 976976 (0.9317169189453125MB)
   84.78829520089286% used
From Space:
   capacity = 131072 (0.125MB)
   used     = 98304 (0.09375MB)
   free     = 32768 (0.03125MB)
   75.0% used
To Space:
   capacity = 131072 (0.125MB)
   used     = 0 (0.0MB)
   free     = 131072 (0.125MB)
   0.0% used
PS Old Generation
   capacity = 35258368 (33.625MB)
   used     = 4119544 (3.9287033081054688MB)
   free     = 31138824 (29.69629669189453MB)
   11.683876009235595% used
PS Perm Generation
   capacity = 52428800 (50.0MB)
   used     = 26075168 (24.867218017578125MB)
   free     = 26353632 (25.132781982421875MB)
   49.73443603515625% used
   ....

    使用jmap -histo[:live] pid檢視堆記憶體中的物件數目、大小統計直方圖,如果帶上live則只統計活物件,如下:

[email protected]:/# jmap -histo:live 21711 | more

 num     #instances         #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$Entry
  18:          1869         138568  [Ljava.util.HashMap$Entry;
  19:          2443          97720  java.util.LinkedHashMap$Entry
  20:          2072          82880  java.lang.ref.SoftReference
  21:          1807          71528  [Ljava.lang.Object;
  22:          2206          70592  java.lang.ref.WeakReference
  23:           934          52304  java.util.LinkedHashMap
  24:           871          48776  java.beans.MethodDescriptor
  25:          1442          46144  java.util.concurrent.ConcurrentHashMap$HashEntry
  26:           804          38592  java.util.HashMap
  27:           948          37920  java.util.concurrent.ConcurrentHashMap$Segment
  28:          1621          35696  [Ljava.lang.Class;
  29:          1313          34880  [Ljava.lang.String;
  30:          1396          33504  java.util.LinkedList$Entry
  31:           462          33264  java.lang.reflect.Field
  32:          1024          32768  java.util.Hashtable$Entry
  33:           948          31440  [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;

    class name是物件型別,說明如下:

B  byte
C  char
D  double
F  float
I  int
J  long
Z  boolean
[  陣列,如[I表示int[]
[L+類名 其他物件

    還有一個很常用的情況是:用jmap把程序記憶體使用情況dump到檔案中,再用jhat分析檢視。jmap進行dump命令格式如下:

jmap -dump:format=b,file=dumpFileName pid

    我一樣地對上面程序ID為21711進行Dump:

[email protected]:/# jmap -dump:format=b,file=/tmp/dump.dat 21711     
Dumping heap to /tmp/dump.dat ...
Heap dump file created

   dump出來的檔案可以用MAT、VisualVM等工具檢視,這裡用jhat檢視:

[email protected]:/# jhat -port 9998 /tmp/dump.dat
Reading from /tmp/dump.dat...
Dump file created Tue Jan 28 17:46:14 CST 2014
Snapshot read, resolving...
Resolving 132207 objects...
Chasing references, expect 26 dots..........................
Eliminating duplicate references..........................
Snapshot resolved.
Started HTTP server on port 9998
Server is ready.

     注意如果Dump檔案太大,可能需要加上-J-Xmx512m這種引數指定最大堆記憶體,即jhat -J-Xmx512m -port 9998 /tmp/dump.dat。然後就可以在瀏覽器中輸入主機地址:9998查看了:

    上面紅線框出來的部分大家可以自己去摸索下,最後一項支援OQL(物件查詢語言)。

D、jstat(JVM統計監測工具)

    語法格式如下:

jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]

    vmid是Java虛擬機器ID,在Linux/Unix系統上一般就是程序ID。interval是取樣時間間隔。count是取樣數目。比如下面輸出的是GC資訊,取樣時間間隔為250ms,取樣數為4:

root@ubuntu:/# jstat -gc 21711 250 4
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT   
192.0  192.0   64.0   0.0    6144.0   1854.9   32000.0     4111.6   55296.0 25472.7    702    0.431   3      0.218    0.649192.0  192.0   64.0   0.0    6144.0   1972.2   32000.0     4111.6   55296.0 25472.7    702    0.431   3      0.218    0.649192.0  192.0   64.0   0.0    6144.0   1972.2   32000.0     4111.6   55296.0 25472.7    702    0.431   3      0.218    0.649192.0  192.0   64.0   0.0    6144.0   2109.7   32000.0     4111.6   55296.0 25472.7    702    0.431   3      0.218    0.649

    要明白上面各列的意義,先看JVM堆記憶體佈局:

    可以看出:

堆記憶體 = 年輕代 + 年老代 + 永久代
年輕代 = Eden區 + 兩個Survivor區(FromTo

    現在來解釋各列含義:

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總耗時

E、hprof(Heap/CPU Profiling Tool)

    hprof能夠展現CPU使用率,統計堆記憶體使用情況。

    語法格式如下:

java -agentlib:hprof[=options] ToBeProfiledClassjava -Xrunprof[:options] ToBeProfiledClassjavac -J-agentlib:hprof[=options] ToBeProfiledClass

    完整的命令選項如下:

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             nformat=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?              ndoe=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

    來幾個官方指南上的例項。

    CPU Usage Sampling Profiling(cpu=samples)的例子:

java -agentlib:hprof=cpu=samples,interval=20,depth=3 Hello

    上面每隔20毫秒取樣CPU消耗資訊,堆疊深度為3,生成的profile檔名稱是java.hprof.txt,在當前目錄。 

    CPU Usage Times Profiling(cpu=times)的例子,它相對於CPU Usage Sampling Profile能夠獲得更加細粒度的CPU消耗資訊,能夠細到每個方法呼叫的開始和結束,它的實現使用了位元組碼注入技術(BCI):

javac -J-agentlib:hprof=cpu=times Hello.java

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

javac -J-agentlib:hprof=heap=sites Hello.java

    Heap Dump(heap=dump)的例子,它比上面的Heap Allocation Profiling能生成更詳細的Heap Dump資訊:

javac -J-agentlib:hprof=heap=dump Hello.java

    雖然在JVM啟動引數中加入-Xrunprof:heap=sites引數可以生成CPU/Heap Profile檔案,但對JVM效能影響非常大,不建議在線上伺服器環境使用

相關推薦

Born To Learn And Share

    現實企業級Java開發中,有時候我們會碰到下面這些問題: OutOfMemoryError,記憶體不足 記憶體洩露 執行緒死鎖 鎖爭用(Lock Contention) Java程序消耗CPU過高 ......     這些問題在日常開發中可能被很多人忽視(比如有的人遇到上面的問題只是重

Android App To Record And Share Your Important Thoughts

Today, am happy to introduce to you my newest android application : Quotes! In a nutshell, this android app helps you record your deepest, perhaps mos

Top 5 SQL and Database Courses to Learn Online

Top 5 SQL and Database Courses to Learn OnlineHello guys, if you are a computer science graduate or new into the programming world and interested in learni

‘I want to learn Artificial Intelligence and Machine Learning. Where can I start?’

How did I get started?My friends and I were building a web startup. It failed. We gave up due to a lack of meaning. But along the way, I was starting to he

Learn How to Code and Deploy Machine Learning Models on Spark Structured Streaming

This post is a token of appreciation for the amazing open source community of Data Science, to which I owe a lot of what I have learned. For last few month

Top 5 Selenium Webdriver with Java Courses for Testers and Developers to Learn Online

The days of manual testing is limited as more and more companies are shifting towards automation testing. This means all manual testing QAs needs to learn

How iLingual Uses Computer Vision AI to Translate and Learn Languages

Omar Alexander Abbas and Raymona Singh are the creators of iLingual, a free app that enables users to learn languages by bringing together machine learning

3 Ways to Learn Spring Core, Spring MVC, Spring Security, and Spring Boot Framework

If you are a Java developer and wants to learn Spring framework then you have come to the right place. In this article, I will share three ways to learn S

Anyone interested for your kids and mine to learn Chinese and English together?

I am from China, have a 6 years boy. I just got this idea that to help him improving English, we might find another English speaking native kid, to learn C

Ask HN: How to learn to document and demo a software product?

I'm a developer and every time I want to demo my projects, I struggle to draw diagrams (functional ones) for documentation and even worse, when I show my t

Top 5 Courses to Learn Shell Scripting in Linux and UNIX Online

A huge chunk of a developer's time is wasted in trying to repeat tasks and commands, especially when it comes to working with a bunch of UNIX or Linux mac

The Best Podcasts, Blogs, and YouTube Channels I Used to Learn UI/UX Design

In the article I wrote last week, I wrote about how to create a system for constant learning. I outlined an 8-step process to help you pick what to learn,

窩上課不聽,how to learn C language easily(1)

程序 簡單 小數 如果 如何 好處 class 數組 指針 C language 學習心得 附:為啥起這麽霸氣側漏,招大神們鄙視的標題,正如我在《C language》隨筆的介紹中寫的,這是一個寫個妹紙們看的C language的文章。沒錯!!寫這篇文章的靈感也來自於上周C

Livemedia-creator- How to create and use a Live CD

download further burning method create Livemedia-creator- How to create and use a Live CDNote for older method (namely for Fedora 23) using livec

Leetcode Best Time to Buy and Sell Stock II

con max and [] python self leet sel ice class Solution: # @param {integer[]} prices # @return {integer} def maxProfit(sel

[Python] How to unpack and pack collection in Python?

ide ont add off art video lec ref show It is a pity that i can not add the video here. As a result, i offer the link as below: How to

[LeetCode] 121. Best Time to Buy and Sell Stock Java

most length 如果 時間復雜度 ase 最大差值 new [1] cas 題目: Say you have an array for which the ith element is the price of a given stock on day i.

[LeetCode] 22. Best Time to Buy and Sell Stock II Java

股票 log ive highlight transacti ever 方法 size 可能 題目: Say you have an array for which the ith element is the price of a given stock on day i

14.Best Time to Buy and Sell Stock

pub 規劃 clas share nbsp return let element his 題目描述: Say you have an array for which the ith element is the price of a given stock on day

leetcode 121. Best Time to Buy and Sell Stock

clas which style ces pre max des sign har Say you have an array for which the ith element is the price of a given stock on day i. If you