java內存溢出分析工具:jmap使用實戰??
?
1 使用命令?
在環境是linux+jdk1.5以上,這個工具是自帶的,路徑在JDK_HOME/bin/下?
jmap -histo pid>a.log?
2 輸出結果摘要?
Size?
-------------------------------------------------------?
353371288?
230711112?
139347160?
76128096?
75782280?
25724272?
9319968 166428?
8533856 32889?
發現有大量的String和自定義對象com.test.util.IPSeeker$IPLocation存在,檢查程序發現此處果然存在內存溢出。修改程序上線后再次用jmap抓取內存數據:?
146881712?
98976352?
42595272?
11515632?
9521896 59808?
8887392 370308?
8704808 155443?
8066880 336120?
內存溢出問題消除。?
注意:這個jmap使用的時候jvm是處在假死狀態的,只能在服務癱瘓的時候為了解決問題來使用,否則會造成服務中斷。
jstack?-- 如果java程序崩潰生成core文件,jstack工具可以用來獲得core文件的java stack和native stack的信息,從而可以輕松地知道java程序是如何崩潰和在程序何處發生問題。另外,jstack工具還可以附屬到正在運行的java程序中,看到 當時運行的java程序的java stack和native stack的信息, 如果現在運行的java程序呈現hung的狀態,jstack是非常有用的。目前只有在Solaris和Linux的JDK版本里面才有。
jconsole?– jconsole是基于Java?Management Extensions (JMX)的實時圖形化監測工具,這個工具利用了內建到JVM里面的JMX指令來提供實時的性能和資源的監控,包括了Java程序的內存使用,Heap size, 線程的狀態,類的分配狀態和空間使用等等。
jinfo?– jinfo可以從core文件里面知道崩潰的Java應用程序的配置信息,目前只有在Solaris和Linux的JDK版本里面才有。
jmap?– jmap 可以從core文件或進程中獲得內存的具體匹配情況,包括Heap size, Perm size等等,目前只有在Solaris和Linux的JDK版本里面才有。
jdb?– jdb 用來對core文件和正在運行的Java進程進行實時地調試,里面包含了豐富的命令幫助您進行調試,它的功能和Sun studio里面所帶的dbx非常相似,但 jdb是專門用來針對Java應用程序的。
jstat?– jstat利用了JVM內建的指令對Java應用程序的資源和性能進行實時的命令行的監控,包括了對Heap size和垃圾回收狀況的監控等等。
jps?– jps是用來查看JVM里面所有進程的具體狀態, 包括進程ID,進程啟動的路徑等等。?
jstatd
啟動jvm監控服務。它是一個基于rmi的應用,向遠程機器提供本機jvm應用程序的信息。默認端口1099。
實例:jstatd -J-Djava.security.policy=my.policy
my.policy文件需要自己建立,內如如下:
grant codebase "file:$JAVA_HOME/lib/tools.jar" {
permission java.security.AllPermission;
};
這是安全策略文件,因為jdk對jvm做了jaas的安全檢測,所以我們必須設置一些策略,使得jstatd被允許作網絡操作
上面的操作沒有通過,出現:
Could not create remote object
access denied (java.util.PropertyPermission java.rmi.server.ignoreSubClasses write)
java.security.AccessControlException: access denied (java.util.PropertyPermission java.rmi.server.ignoreSubClasses write)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)
at java.security.AccessController.checkPermission(AccessController.java:546)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at java.lang.System.setProperty(System.java:727)
at sun.tools.jstatd.Jstatd.main(Jstatd.java:122)
create in your usr/java/bin the jstatd.all.policy file, with the content must be
- grant?codebase?"file:${java.home}/../lib/tools.jar"?{ ?
- permission?java.security.AllPermission; ?
- };?
jps
列出所有的jvm實例
實例:
jps
列出本機所有的jvm實例
jps 192.168.0.77
列出遠程服務器192.168.0.77機器所有的jvm實例,采用rmi協議,默認連接端口為1099
(前提是遠程服務器提供jstatd服務)
輸出內容如下:
jones@jones:~/data/ebook/java/j2se/jdk_gc$ jps
6286 Jps
6174? Jstat
jconsole
一個圖形化界面,可以觀察到java進程的gc,class,內存等信息。雖然比較直觀,但是個人還是比較傾向于使用jstat命令(在最后一部分會對jstat作詳細的介紹)。
jinfo(linux下特有)
觀察運行中的java程序的運行環境參數:參數包括Java System屬性和JVM命令行參數
實例:jinfo 2083
其中2083就是java進程id號,可以用jps得到這個id號。
輸出內容太多了,不在這里一一列舉,大家可以自己嘗試這個命令。
jstack(linux下特有)
可以觀察到jvm中當前所有線程的運行情況和線程當前狀態
jstack 2083
輸出內容如下:
jmap(linux下特有,也是很常用的一個命令)
觀察運行中的jvm物理內存的占用情況。
參數如下:
-heap:打印jvm heap的情況
-histo:打印jvm heap的直方圖。其輸出信息包括類名,對象數量,對象占用大小。
-histo:live :同上,但是只答應存活對象的情況
-permstat:打印permanent generation heap情況
命令使用:
jmap -heap 2083
可以觀察到New Generation(Eden Space,From Space,To Space),tenured generation,Perm Generation的內存使用情況
輸出內容:
jmap -histo 2083 | jmap -histo:live 2083
可以觀察heap中所有對象的情況(heap中所有生存的對象的情況)。包括對象數量和所占空間大小。
輸出內容:
寫個腳本,可以很快把占用heap最大的對象找出來,對付內存泄漏特別有效。
jstat
最后要重點介紹下這個命令。
這是jdk命令中比較重要,也是相當實用的一個命令,可以觀察到classloader,compiler,gc相關信息
具體參數如下:
-class:統計class loader行為信息
-compile:統計編譯行為信息
-gc:統計jdk gc時heap信息
-gccapacity:統計不同的generations(不知道怎么翻譯好,包括新生區,老年區,permanent區)相應的heap容量情況
-gccause:統計gc的情況,(同-gcutil)和引起gc的事件
-gcnew:統計gc時,新生代的情況
-gcnewcapacity:統計gc時,新生代heap容量
-gcold:統計gc時,老年區的情況
-gcoldcapacity:統計gc時,老年區heap容量
-gcpermcapacity:統計gc時,permanent區heap容量
-gcutil:統計gc時,heap情況
-printcompilation:不知道干什么的,一直沒用過。
一般比較常用的幾個參數是:
jstat -class 2083 1000 10 (每隔1秒監控一次,一共做10次)
輸出內容含義如下:
Loaded | Number of classes loaded. |
Bytes | Number of Kbytes loaded. |
Unloaded | Number of classes unloaded. |
Bytes | Number of Kbytes unloaded. |
Time | Time spent performing class load and unload operations. |
jstat -gc 2083 2000 20(每隔2秒監控一次,共做10)
輸出內容含義如下:
S0C | Current survivor space 0 capacity (KB). |
EC | Current eden space capacity (KB). |
EU | Eden space utilization (KB). |
OC | Current old space capacity (KB). |
OU | Old space utilization (KB). |
PC | Current permanent space capacity (KB). |
PU | Permanent space utilization (KB). |
YGC | Number of young generation GC Events. |
YGCT | Young generation garbage collection time. |
FGC | Number of full GC events. |
FGCT | Full garbage collection time. |
GCT | Total garbage collection time. |
輸出內容:

如果能熟練運用這些命令,尤其是在linux下,那么完全可以代替jprofile等監控工具了,誰讓它收費呢。呵呵。
用命令的好處就是速度快,并且輔助于其他命令,比如grep gawk sed等,可以組裝多種符合自己需求的工具。
u??????????????jps的用法
用來查看JVM里面所有進程的具體狀態,?包括進程ID,進程啟動的路徑等等。與unix上的ps類似,用來顯示本地的java進程,可以查看本地運行著幾個java程序,并顯示他們的進程號。
?
[root@localhost ~]# jps
25517 Jps
25444 Bootstrap
??jstack的用法
如果java程序崩潰生成core文件,jstack工具可以用來獲得core文件的java stack和native stack的信息,從而可以輕松地知道java程序是如何崩潰和在程序何處發生問題。另外,jstack工具還可以附屬到正在運行的java程序中,看到當時運行的java程序的java stack和native stack的信息,?如果現在運行的java程序呈現hung的狀態,jstack是非常有用的。目前只有在Solaris和Linux的JDK版本里面才有。
?
[root@localhost bin]# jstack?25444
Attaching to process ID 25917, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 1.5.0_08-b03
Thread 25964: (state = BLOCKED)
Error occurred during stack walking:
sun.jvm.hotspot.debugger.DebuggerException: sun.jvm.hotspot.debugger.DebuggerException: get_thread_regs failed for a lwp
????????at sun.jvm.hotspot.debugger.linux.LinuxDebuggerLocal$LinuxDebuggerLocalWorkerThread.execute(LinuxDebuggerLocal.java:134)
????????at sun.jvm.hotspot.debugger.linux.LinuxDebuggerLocal.getThreadIntegerRegisterSet(LinuxDebuggerLocal.java:437)
????????at sun.jvm.hotspot.debugger.linux.LinuxThread.getContext(LinuxThread.java:48)
????????at
jstat的用法
用以判斷JVM是否存在內存問題呢?如何判斷JVM垃圾回收是否正常?一般的top指令基本上滿足不了這樣的需求,因為它主要監控的是總體的系統資源,很難定位到java應用程序。
Jstat是JDK自帶的一個輕量級小工具。全稱“Java Virtual Machine statistics monitoring tool”,它位于java的bin目錄下,主要利用JVM內建的指令對Java應用程序的資源和性能進行實時的命令行的監控,包括了對Heap size和垃圾回收狀況的監控。可見,Jstat是輕量級的、專門針對JVM的工具,非常適用。由于JVM內存設置較大,圖中百分比變化不太明顯
一個極強的監視VM內存工具。可以用來監視VM內存內的各種堆和非堆的大小及其內存使用量。
jstat工具特別強大,有眾多的可選項,詳細查看堆內各個部分的使用量,以及加載類的數量。使用時,需加上查看進程的進程id,和所選參數。
?
?
語法結構:
Usage: jstat -help|-options
???????jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
?
參數解釋:
Options —?選項,我們一般使用?-gcutil?查看gc情況
vmid??? — VM的進程號,即當前運行的java進程號
interval–?間隔時間,單位為秒或者毫秒
count?? —?打印次數,如果缺省則打印無數次
?
S0? — Heap上的?Survivor space 0?區已使用空間的百分比
S1? — Heap上的?Survivor space 1?區已使用空間的百分比
E?? — Heap上的?Eden space?區已使用空間的百分比
O?? — Heap上的?Old space?區已使用空間的百分比
P?? — Perm space?區已使用空間的百分比
YGC —?從應用程序啟動到采樣時發生?Young GC?的次數
YGCT–?從應用程序啟動到采樣時?Young GC?所用的時間(單位秒)
FGC —?從應用程序啟動到采樣時發生?Full GC?的次數
FGCT–?從應用程序啟動到采樣時?Full GC?所用的時間(單位秒)
GCT —?從應用程序啟動到采樣時用于垃圾回收的總時間(單位秒)
?
實例使用1:
[root@localhost bin]# jstat -gcutil 25444
??S0?????S1?????E??????O??????P?????YGC?????YGCT????FGC????FGCT?????GCT
?11.63???0.00???56.46??66.92??98.49 162????0.248????6??????0.331????0.579
?
實例使用2:
[root@localhost bin]# jstat -gcutil 25444 1000 5
??S0?????S1?????E??????O??????P?????YGC?????YGCT????FGC????FGCT?????GCT
?73.54???0.00??99.04??67.52??98.49????166????0.252?????6????0.331????0.583
?73.54???0.00??99.04??67.52??98.49????166????0.252?????6????0.331????0.583
?73.54???0.00??99.04??67.52??98.49????166????0.252?????6????0.331????0.583
?73.54???0.00??99.04??67.52??98.49????166????0.252?????6????0.331????0.583
?73.54???0.00??99.04??67.52??98.49????166????0.252?????6????0.331????0.583
?
我們可以看到,5次young gc之后,垃圾內存被從Eden space區(E)放入了Old space區(O),并引起了百分比的變化,導致Survivor space使用的百分比從73.54%(S0)降到0%(S1)。有效釋放了內存空間。綠框中,我們可以看到,一次full gc之后,Old space區(O)的內存被回收,從99.05%降到67.52%。
圖中同時打印了young gc和full gc的總次數、總耗時。而,每次young gc消耗的時間,可以用相間隔的兩行YGCT相減得到。每次full gc消耗的時間,可以用相隔的兩行FGCT相減得到。例如紅框中表示的第一行、第二行之間發生了1次young gc,消耗的時間為0.252-0.252=0.0秒。
常駐內存區(P)的使用率,始終停留在98.49%左右,說明常駐內存沒有突變,比較正常。
如果young gc和full gc能夠正常發生,而且都能有效回收內存,常駐內存區變化不明顯,則說明java內存釋放情況正常,垃圾回收及時,java內存泄露的幾率就會大大降低。但也不能說明一定沒有內存泄露。
GCT?是YGCT?和FGCT的時間總和。
以上,介紹了Jstat按百分比查看gc情況的功能。其實,它還有功能,例如加載類信息統計功能、內存池信息統計功能等,那些是以絕對值的形式打印出來的,比較少用,在此就不做介紹。
?
[root@localhost bin]# ps -ef | grep java
root?????25917?????1??2 23:23?pts/2????00:00:05 /usr/local/jdk1.5/bin/java -Djava.endorsed.dirs=/usr/local/jakarta-tomcat-5.0.30/common/endorsed -classpath /usr/local/jdk1.5/lib/tools.jar:/usr/local/jakarta-tomcat-5.0.30/bin/bootstrap.jar:/usr/local/jakarta-tomcat-5.0.30/bin/commons-logging-api.jar -Dcatalina.base=/usr/local/jakarta-tomcat-5.0.30 -Dcatalina.home=/usr/local/jakarta-tomcat-5.0.30 -Djava.io.tmpdir=/usr/local/jakarta-tomcat-5.0.30/temp org.apache.catalina.startup.Bootstrap start
?
jstat -class pid:顯示加載class的數量,及所占空間等信息。
實例使用3:
[root@localhost bin]# jstat -class 25917
Loaded??Bytes??Unloaded??Bytes?????Time
2629????2916.8???????29???24.6?????0.90
?
jstat -compiler pid:顯示VM實時編譯的數量等信息。
實例使用4:
[root@localhost bin]# jstat -compiler 25917
Compiled Failed Invalid???Time???FailedType FailedMethod
?????768??????0???????0???0.70????????????0
?
jstat –gccapacity :可以顯示,VM內存中三代(young,old,perm)對象的使用和占用大小,如:PGCMN顯示的是最小perm的內存使用量,PGCMX顯示的是perm的內存最大使用量,PGC是當前新生成的perm內存占用量,PC是但前perm內存占用量。其他的可以根據這個類推,?OC是old內純的占用量。
?
[root@localhost bin]# jstat -gccapacity 25917
NGCMN???????640.0
NGCMX???????4992.0
NGC?????????832.0
S0C?????????64.0
S1C?????????64.0
EC??????????704.0
OGCMN???????1408.0
OGCMX???????60544.0
OGC?????????9504.0
OC??????????9504.0??????????????????OC是old內純的占用量
PGCMN???????8192.0??????????????????PGCMN顯示的是最小perm的內存使用量
PGCMX???????65536.0?????????????????PGCMX顯示的是perm的內存最大使用量
PGC?????????12800.0?????????????????PGC是當前新生成的perm內存占用量
PC??????????12800.0?????????????????PC是但前perm內存占用量
YGC?????????164
FGC?????????6
?
jstat -gcnew pid: new對象的信息
[root@localhost bin]# jstat -gcnew 25917
?S0C????S1C????S0U????S1U???TT MTT??DSS??????EC???????EU?????YGC?????YGCT
?64.0???64.0???47.4???0.0???2??15???32.0????704.0????145.7????168????0.254
?
jstat -gcnewcapacity pid: new對象的信息及其占用量
[root@localhost bin]# jstat -gcnewcapacity 25917
?NGCMN??NGCMX???NGC???S0CMX??S0C???S1CMX??S1C???ECMX????EC??????YGC???FGC
640.0??4992.0??832.0 64.0???448.0 448.0??64.0???4096.0??704.0??168?????6
?
jstat -gcold pid: old對象的信息。
[root@localhost bin]# jstat -gcold 25917
???PC???????PU????????OC??????????OU???????YGC????FGC????FGCT?????GCT
?12800.0??12617.6?????9504.0??????6561.3???169?????6????0.335????0.591
?
jstat -gcoldcapacity pid:old對象的信息及其占用量。
[root@localhost bin]# jstat -gcoldcapacity 25917
OGCMN??????OGCMX????????OGC?????????OC???????YGC???FGC????FGCT?????GCT
1408.0?????60544.0??????9504.0??????9504.0???169?????6????0.335????0.591
?
jstat -gcpermcapacity pid: perm對象的信息及其占用量。
[root@localhost bin]# jstat -gcpermcapacity 25917
PGCMN??????PGCMX???????PGC?????????PC??????YGC???FGC????FGCT?????GCT
8192.0????65536.0????12800.0????12800.0???169?????6????0.335????0.591
?
jstat -printcompilation pid:當前VM執行的信息。
[root@localhost bin]# jstat -printcompilation -h3??25917 1000 5
每1000毫秒打印一次,一共打印5次,還可以加上-h3每三行顯示一下標題。
Compiled??Size??Type Method
?????788?????73????1 java/io/File <init>
?????788?????73????1 java/io/File <init>
?????788?????73????1 java/io/File <init>
Compiled??Size??Type Method
?????788?????73????1 java/io/File <init>
?????788?????73????1 java/io/File <init>
???jmap的用法
打印出某個java進程(使用pid)內存內的,所有‘對象’的情況(如:產生那些對象,及其數量)。
可以輸出所有內存中對象的工具,甚至可以將VM?中的heap,以二進制輸出成文本。使用方法?jmap -histo pid。如果連用SHELL jmap -histo pid>a.log可以將其保存到文本中去,在一段時間后,使用文本對比工具,可以對比出GC回收了哪些對象。jmap -dump:format=b,file=String 3024可以將3024進程的內存heap輸出出來到String文件里。
?
[root@localhost bin]# jmap -histo??25917
Attaching to process ID 26221, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 1.5.0_08-b03
Iterating over heap. This may take a while...
Unknown oop at 0xaa6e42d0
Oop's klass is null
?
Object Histogram:
?
Size????Count???Class description
-------------------------------------------------------
3722768 30467???* ConstMethodKlass
1976480 25334???char[]
1907880 46994???* SymbolKlass
1762088 2947????byte[]
1709536 30467???* MethodKlass
1487816 2600????* ConstantPoolKlass
1009576 2600????* InstanceKlassKlass
904880??2199????* ConstantPoolCacheKlass
741432??30893???java.lang.String
653576??4785????int[]
351760??4397????java.lang.reflect.Method
277824??2894????java.lang.Class
248704??3401????short[]
200888??4411????java.lang.Object[]
193656??4045????java.lang.Object[]
179744??5617????java.util.TreeMap$Entry
175688??1800????java.util.HashMap$Entry[]
165288??6887????java.util.HashMap$Entry
104736??3273????java.lang.ref.SoftReference
104136??4339????java.lang.ref.WeakReference
96096???3521????java.lang.String[]
86160???3590????java.util.Hashtable$Entry
85584???3566????java.util.ArrayList
83472???1206????java.util.Hashtable$Entry[]
82944???1728????java.beans.MethodDescriptor
80560???265?????* ObjArrayKlassKlass
69120???1728????java.util.HashMap
52464???3055????java.lang.Class[]
43040???1076????java.util.Hashtable
42496???664?????org.apache.commons.modeler.AttributeInfo
37880???947?????java.util.TreeMap
33896???557?????javax.management.modelmbean.ModelMBeanAttributeInfo[]
33152???518?????java.beans.PropertyDescriptor
616?????11??????org.springframework.aop.framework.ProxyFactory
608?????19??????java.util.PropertyPermission
608?????38??????org.springframework.beans.MutablePropertyValues
608?????38??????org.springframework.beans.factory.support.MethodOverrides
608?????2???????* ArrayKlassKlass
608?????38??????org.springframework.beans.factory.config.ConstructorArgumentValues
608?????4???????org.apache.xerces.impl.XMLDTDScannerImpl
576?????24??????java.util.Stack
576?????36??????java.util.regex.Pattern$Category
576?????24??????org.apache.naming.NamingEntry
560?????7???????java.net.URL[]
552?????23??????sun.management.MappedMXBeanType$BasicMXBeanType
552?????1???????java.util.Locale[]
552?????22??????java.io.ObjectStreamField[]
544?????17??????java.util.Collections$SynchronizedMap
176?????11??????java.util.regex.Pattern$Ctype
8???????1???????sun.reflect.GeneratedMethodAccessor49
8???????1???????sun.reflect.GeneratedMethodAccessor6
8???????1???????sun.reflect.GeneratedConstructorAccessor10
Heap traversal took 12.003 seconds.
?
u??????????????jinfo的用法
可以輸出并修改運行時的java?進程的opts。用處比較簡單,就是能輸出并修改運行時的java進程的運行參數。用法是jinfo?-opt? pid?如:查看2788的MaxPerm大小可以用??jinfo?-flag MaxPermSize 2788。
?
?
u??????????????jconsole的用法
jconsole:一個java GUI監視工具,可以以圖表化的形式顯示各種數據。并可通過遠程連接監視遠程的服務器VM。
用java寫的GUI程序,用來監控VM,并可監控遠程的VM,非常易用,而且功能非常強。命令行里打?jconsole,選則進程就可以了
不過我沒有運行起來,老是報下面的錯。會的朋友,幫忙看看。
?[root@localhost bin]# jconsole
Exception in thread "AWT-EventQueue-0" java.awt.HeadlessException:
No X11 DISPLAY variable was set, but this program performed an operation which requires it.????????at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:159)
????????at java.awt.Window.<init>(Window.java:317)
????????at java.awt.Frame.<init>(Frame.java:419)
????????at javax.swing.JFrame.<init>(JFrame.java:194)
????????at sun.tools.jconsole.JConsole.<init>(JConsole.java:65)
????????at sun.tools.jconsole.JConsole$4.run(JConsole.java:666)
????????at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
????????at java.awt.EventQueue.dispatchEvent(EventQueue.java:461)
????????at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:242)
????????at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163)
????????at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157)
????????at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149)
????????at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)
u??????????????jdb的用法
用來對core文件和正在運行的Java進程進行實時地調試,里面包含了豐富的命令幫助您進行調試,它的功能和Sun studio里面所帶的dbx非常相似,但?jdb是專門用來針對Java應用程序的。
JProfiler在java程序性能調試方便表現優越,推薦使用。也可使用下面jdk自己的一些工具。
所有工具都在JDK/bin目錄下, jconsole和jvisualvm為GUI圖形化工具,其他為命令行。
jvisualvm: GUI工具,可監控、性能評估、故障診斷主機上所有java進程的cpu,內存,線程使用情況,類似于JProfiler,嚴重推薦。
jinfo:可以輸出并修改運行時的java 進程的opts。
jps:與unix上的ps類似,用來顯示本地的java進程,可以查看本地運行著幾個java程序,并顯示他們的進程號。
jstat:一個極強的監視VM內存工具。可以用來監視VM內存內的各種堆和非堆的大小及其內存使用量。
jmap:打印出某個java進程(使用pid)內存內的,所有‘對象’的情況(如:產生那些對象,及其數量)。
jconsole:一個java GUI監視工具,可以以圖表化的形式顯示各種數據。并可通過遠程連接監視遠程的服務器VM。
jstat工具特別強大,有眾多的可選項,詳細查看堆內各個部分的使用量,以及加載類的數量。使用時,需加上查看進程的進程id,和所選參數。以下詳細介紹各個參數的意義。
jstat -class pid:顯示加載class的數量,及所占空間等信息。
jstat -compiler pid:顯示VM實時編譯的數量等信息。
jstat -gc pid:可以顯示gc的信息,查看gc的次數,及時間。其中最后五項,分別是young gc的次數,young gc的時間,full gc的次數,full gc的時間,gc的總時間。
jstat -gccapacity:可以顯示,VM內存中三代(young,old,perm)對象的使用和占用大小,如:PGCMN顯示的是最小perm的內存使用量,PGCMX顯示的是perm的內存最大使用量,PGC是當前新生成的perm內存占用量,PC是但前perm內存占用量。其他的可以根據這個類推, OC是old內純的占用量。
jstat -gcnew pid:new對象的信息。
jstat -gcnewcapacity pid:new對象的信息及其占用量。
jstat -gcold pid:old對象的信息。
jstat -gcoldcapacity pid:old對象的信息及其占用量。
jstat -gcpermcapacity pid: perm對象的信息及其占用量。
jstat -util pid:統計gc信息統計。
jstat -printcompilation pid:當前VM執行的信息。
除了以上一個參數外,還可以同時加上 兩個數字,如:jstat -printcompilation 3024 250 6是每250毫秒打印一次,一共打印6次,還可以加上-h3每三行顯示一下標題。
jmap是一個可以輸出所有內存中對象的工具,甚至可以將VM 中的heap,以二進制輸出成文本。使用方法 jmap -histo pid。如果連用SHELL jmap -histo pid>a.log可以將其保存到文本中去,在一段時間后,使用文本對比工具,可以對比出GC回收了哪些對象。jmap -dump:format=b,file=String 3024可以將3024進程的內存heap輸出出來到String文件里。
jinfo:的用處比較簡單,就是能輸出并修改運行時的java進程的運行參數。用法是jinfo -opt? pid 如:查看2788的MaxPerm大小可以用? jinfo -flag MaxPermSize 2788。
jconsole是一個用java寫的GUI程序,用來監控VM,并可監控遠程的VM,非常易用,而且功能非常強。由于是GUI程序,這里就不詳細介紹了,不會的地方可以參考SUN的官方文檔。
使用方法:命令行里打 jconsole,選則進程就可以了。
SUN官方說明:
jvisualvm:?http://java.sun.com/javase/6/docs/technotes/tools/share/jvisualvm.html
jps:http://java.sun.com/javase/6/docs/technotes/tools/share/jps.html
jstat:http://java.sun.com/javase/6/docs/technotes/tools/share/jstat.html
jmap:http://java.sun.com/javase/6/docs/technotes/tools/share/jmap.html
jconsole:http://java.sun.com/javase/6/docs/technotes/tools/share/jconsole.html
在一次解決系統tomcat老是內存撐到頭,然后崩潰的問題時,使用到了jmap。?
1 使用命令?
在環境是linux+jdk1.5以上,這個工具是自帶的,路徑在JDK_HOME/bin/下?
jmap -histo pid>a.log?
2 輸出結果摘要?
Size??? Count?? Class description?
-------------------------------------------------------?
353371288?????? 9652324 char[]?
230711112?????? 9612963 java.lang.String?
139347160?????? 114865? byte[]?
76128096??????? 3172004 java.util.Hashtable$Entry?
75782280??????? 3157595 com.test.util.IPSeeker$IPLocation?
25724272??????? 9115??? java.util.Hashtable$Entry[]?
9319968 166428? org.apache.tomcat.util.buf.MessageBytes?
8533856 32889?? int[]?
發現有大量的String和自定義對象com.test.util.IPSeeker$IPLocation存在,檢查程序發現此處果然存在內存溢出。修改程序上線后再次用jmap抓取內存數據:
146881712?? 207163? byte[]?
98976352??? 354285? char[]?
42595272??? 53558?? int[]?
11515632??? 479818? java.util.HashMap$Entry?
9521896 59808?? java.util.HashMap$Entry[]?
8887392 370308? com.test.bean.UnionIPEntry?
8704808 155443? org.apache.tomcat.util.buf.MessageBytes?
8066880 336120? java.lang.String?
內存溢出問題消除。?
注意:這個jmap使用的時候jvm是處在假死狀態的,只能在服務癱瘓的時候為了解決問題來使用,否則會造成服務中斷。
一.Java VisualVM 概述
? 對于使用命令行遠程監控jvm?太麻煩?。?在jdk1.6?中?Oracle?提供了一個新的可視化的。?JVM?監控工具?Java?VisualVM?。jvisualvm.exe?在JDK?的?bin?目錄下。
?
???雙擊啟動?Java?VisualVM?后可以看到窗口左側?“應用程序?”欄中有“?本地?”、“遠程?”?、“快照?”三個項目。
?
??“本地?”下顯示的是在?localhost?運行的?Java?程序的資源占用情況,如果本地有?Java?程序在運行的話啟動?Java?VisualVM?即可看到相應的程序名,點擊程序名打開相應的資源監控菜單,以圖形的形式列出程序所占用的?CPU?、?Heap?、?PermGen?、類、線程的?統計信息。
??“遠程”?項下列出的遠程主機上的?Java?程序的資源占用情況,但需要在遠程主機上運行?jstatd?守護程序
?

VisualVM分為?3?類,?本地?它會自動偵測到,并顯示出來
雙擊Local?下的任一節點,看到右邊的變化?,你可以監控?CPU?,內存,類,線程等運行狀況,實時監控服務器性能。
?

?右鍵?VisualVM我們可以看到?Thread?Dump,?Heap?Dump
?做?Thread?Dump?很快,馬上就可以看到結果
?

?
Heap?Dump要稍花費一些時間(可以看到當前?heap?里對象的數量及占用的比例,做?OOM?很好用)
?

?
?
對其功能不再做描述,可以查閱網上相關質量,我們主要講的是如何使用?VisualVM?遠程監控。
二.使用visualvm 遠程監控 JVM??
1.?測試環境
Ubuntu?Server?10.01
?
2.??在服務器上安裝?jstatd?組件
使用apt-get?命令安裝?openjdk?即可?:
?

- sudo?apt-get?install?openjdk-6-jdk??
?
3.?在服務器上配置?jstatd?的?security?policy?文件
?? jstatd是一個監控?JVM?從創建到銷毀過程中資源占用情況并提供遠程監控接口的?RMI?(?Remote?Method?Invocation?,遠程方法調用)服務器程序,它是一個?Daemon?程序,要保證遠程監控軟件連接到本地的話需要?jstatd?始終保持運行。?
?? jstatd運行需要通過?-J-Djava.security.policy=***?指定安全策略,因此我們需要在服務器上建立一個指定安全策略的文件jstatd.all.policy?,文件內容如下:
?

- grant?codebase?"file:${java.home}/../lib/tools.jar"?{??
- ???permission?java.security.AllPermission;??
- };??
?

?
4.?修改服務器?hosts?文件中的?IP?地址
?
?? 要使Java?VisualVM?成功連接到遠程服務器上,服務器端應該在?/etc/hosts?文件中把本機地址設為本機的?IP?地址。使用?hostname?-i?命令查看,如果顯示的是?127.0.0.1?或者與本機實際?IP?不一致的話,需要把?/etc/hosts?文件中相應的地址改為本機實際?IP?。
?
5.?運行?jstatd?守護程序
?
? 由于?jstatd?需要保持一直運行,所以建議使用?screen?命令執行?jstatd?程序,命令如下:

- screen?jstatd?-J-Djava.security.policy=jstatd.all.policy??
?
如果需要RMI?日志功能的話,還可以在啟動參數中加入?-J-Djava.rmi.server.logCalls=true?。

- screen?jstatd?-J-Djava.security.policy=jstatd.all.policy?-J-Djava.rmi.server.logCalls=true??
?

?
jstatd開始運行后,使用?CTRL+A+D?斷開?screen?界面,回到?shell?界面。如果想切換回?jstatd?運行界面的話,使用?screen?-r?-d?命令即可。
?
6.?通過Java?VisualVM?連接到服務器監控?Java?程序
?? 在Java?VisualVM?程序窗口左側?“?遠程?”?項目右鍵選擇?“?添加遠程主機?”?,在彈出的對話框中輸入遠程主機的?IP?地址,確認提交后即可看到相應的遠程主機和在上面運行的?Java?程序,連接成功后應該會顯示?Jstatd?及其?PID?。

?

?
? 通過以上方式連接服務器發現一個問題,不能監控CPU?。提示我們建立?JMX?,建立?JMX?提示要求端口號。(?JMX:Java?Management?Extensions?,即?Java?管理擴展?,?是一個為應用程序、設備、系統等植入管理功能的框架。?JMX?可以跨越一系列異構操作系統平臺、系統體系結構和?網絡傳輸協議,靈活的開發無縫集成的系統、網絡和服務管理應用?。而?Visual?VM是通過?JMX?來和遠程?Java?應用聯系的?)。
?

?
7.?T?omcat中配置
? 下面我們為54?服務器的?tomcat?配置?jvm?啟動參數。?在?tomcat?的?catalina.sh?中添加如下參數:

- JAVA_OPTS='-Dcom.sun.management.jmxremote.port=8999?-Dcom.sun.management.jmxremote.ssl=false?-Dcom.sun.management.jmxremote.authenticate=false'???
?
或:

- JAVA_OPTS=’-Dcom.sun.management.jmxremote.port=1099?-Dcom.sun.management.jmxremote.ssl=false?-Dcom.sun.management.jmxremote.authenticate=false?-Djava.rmi.server.hostname=192.168.1.54??其他配置’??
?

?
注:1.?-Dcom.sun.management.jmxremote.port?:這個是配置遠程?connection?的端口號的,要確定這個端口沒有被占用
2.?-Dcom.sun.management.jmxremote.ssl=false?指定了?JMX?是否啟用?ssl
3.?-Dcom.sun.management.jmxremote.authenticate=false???指定了JMX?是否啟用鑒權(需要用戶名,密碼鑒權)
?? 2,3兩個是固定配置,是?JMX?的遠程服務權限的
4.?-Djava.rmi.server.hostname?:這個是配置?server?的?IP?的
?
?

連接成功,現在我們可以遠程監控服務器性能,可以配合?jmeter?進行了一個長時間的加壓,在加壓過程中重點關注了系統資源的使用情況。

三.參考博客
http://mahuihuang.blog.163.com/blog/static/745292520113202321494/
?
http://wolfdream.iteye.com/blog/1032712
?
http://sjsky.iteye.com/blog/705323