JDK自帶的工具能夠方便的幫助咱們處理一些問題,包括查看JVM參數,分析內存變化,查看內存區域,查看線程等信息。html
咱們熟悉的有java.exe,javac.exe,javap.exe(偶爾用),jps.exe,jmap.exe....等,下面會詳細介紹。分別在linux和windows下面介紹。windows與linux下面使用的都是JDK1.7.0_80java
windows下的jdk版本以下:linux
$ java -version java version "1.7.0_80" Java(TM) SE Runtime Environment (build 1.7.0_80-b15) Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)
linux下的JDK版本以下:spring
[root@VM_0_12_centos ~]# java -version java version "1.7.0_80" Java(TM) SE Runtime Environment (build 1.7.0_80-b15) Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)
$ dir
appletviewer.exe java-rmi.exe jrunscript.exe pack200.exe
apt.exe javaw.exe jsadebugd.exe policytool.exe
extcheck.exe javaws.exe jstack.exe rmic.exe
idlj.exe jcmd.exe jstat.exe rmid.exe
jabswitch.exe jconsole.exe jstatd.exe rmiregistry.exe
jar.exe jdb.exe jvisualvm.exe schemagen.exe
jarsigner.exe jhat.exe keytool.exe serialver.exe
java.exe jinfo.exe kinit.exe servertool.exe
javac.exe jli.dll klist.exe tnameserv.exe
javadoc.exe jmap.exe ktab.exe unpack200.exe
javafxpackager.exe jmc.exe msvcr100.dll wsgen.exe
javah.exe jmc.ini native2ascii.exe wsimport.exe
javap.exe jps.exe orbd.exe xjc.exe
[root@VM_0_12_centos bin]# ls appletviewer javac jconsole jps native2ascii serialver apt javadoc jcontrol jrunscript orbd servertool ControlPanel javafxpackager jdb jsadebugd pack200 tnameserv extcheck javah jhat jstack policytool unpack200 idlj javap jinfo jstat rmic wsgen jar java-rmi.cgi jmap jstatd rmid wsimport jarsigner javaws jmc jvisualvm rmiregistry xjc java jcmd jmc.ini keytool schemagen
其實上面的工具大部分都是jdk/lib/tools.jar 類庫的一層包裝而已,它們主要的功能代碼是在tools.jar中實現的。apache
研究常見的工具的使用。主要有下面工具:windows
jps---JVM Process Status tool,顯示指定系統內全部的HotSpot虛擬機進程centos
jstat---JVM Statistics Monitoring tool,用於收集HotSpot虛擬機各方面的運行數據數組
jinfo---Configuration Info For Java,顯示虛擬機配置信息瀏覽器
jmap---Memory Map for Java,生成虛擬機的內存轉儲快照(heapdump文件)tomcat
jhat---JVM Heap Dump Browser,用於分析heapdump文件,它會創建一個http/html服務器。讓用於能夠在瀏覽器上查看分析結果
jstack---Stack Trace For Java,顯示虛擬機的線程快照。
下面研究具體的使用。
JDK的不少工具都參考了UNIX系統的命名方式,jps(JVM Process Status)是其中的典型。除了名字像JVM的ps以外,功能也和UNIX的ps差很少:能夠列出正在運行的虛擬機進程,並顯示虛擬機執行主類(Main Class,main函數所在的類)名稱以及這些進程的本地虛擬機惟一ID(Local Vitural Machine Identifier,LVMID)。雖然功能比較單一,但它是使用最頻繁的JDK命令行工具,由於其餘工具的使用都須要依賴此工具識別處的LVMID做爲輸入。對於本地虛擬機進程來講,LVMID與操做系統的進行ID(Process Identifier,PID)是一致的,使用windows的任務管理器或者unix的ps命令也能夠查詢到虛擬機的LVMID,可是若是啓動了多個虛擬機進程,沒法根據名稱定位時,那就只能根據jps來區分了。
jps命令格式:
jps [option] [hostid]
例如:
C:\Users\Administrator>jps -l 2204 org.apache.catalina.startup.Bootstrap 2084 6596 sun.tools.jps.Jps
jps能夠經過RMI協議查詢開啓了RMI服務的遠程虛擬機進程狀態,hostid爲RMI註冊表中註冊的主機名。jps的常見其餘選項以下:
-q 只輸出LVMID,省略主類的名稱
-m 輸出虛擬機進程啓動時傳遞給主類main函數的參數
-l 輸出主類的全名,若是進程執行的是jar包,輸出Jar路徑
-v 輸出虛擬機進程啓動時JVM參數
本身在windows下面的測試:
C:\Users\Administrator>jps -m -l -v 9772 sun.tools.jps.Jps -m -l -v -Denv.class.path=.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar -Dapplication.home=C:\Program Files\Java\jdk1.7.0_80 -Xms8m 2204 org.apache.catalina.startup.Bootstrap start -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:53302 -Dcatalina.base=E:\xiangmu\.metadata\.plugins\org.eclipse.wst.server.core\tmp1 -Dcatalina.home=E:\tomcat\apache-tomcat-7.0.88 -Dwtp.deploy=E:\xiangmu -Djava.endorsed.dirs=E:\tomcat\apache-tomcat-7.0.88\endorsed -Dfile.encoding=UTF-8 2084 -Dosgi.requiredJavaVersion=1.7 -Xms256m -Xmx1024m -Xloggc:gc.log -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Dsun.lang.ClassLoader.allowArraySyntax=true -XX:MaxPermSize=256m
9772是jps命令自身,可見jps自己也是一個Java程序,其主類位於sun.tools.jps.Jps(該類位於jdk/lib/tools.jar)
2204 是本身啓動的一個tomcat程序,主類是Bootstrap,向main函數傳遞的參數是start,後面是一些設置
2084是Eclipse的PID,後面跟着eclipse.ini中對eclipse的設置(這也能夠用來判斷eclipse啓動參數)
本身在linux下面的測試
[root@VM_0_12_centos ~]# jps -m -l -v 4211 sun.tools.jps.Jps -m -l -v -Denv.class.path=.:/opt/java/jdk1.7.0_80/lib:/opt/java/jdk1.7.0_80/jre/lib -Dapplication.home=/opt/java/jdk1.7.0_80 -Xms8m 21991 org.apache.catalina.startup.Bootstrap start -Djava.util.logging.config.file=/opt/apache-tomcat/apache-tomcat-7.0.72/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.endorsed.dirs=/opt/apache-tomcat/apache-tomcat-7.0.72/endorsed -Dcatalina.base=/opt/apache-tomcat/apache-tomcat-7.0.72 -Dcatalina.home=/opt/apache-tomcat/apache-tomcat-7.0.72 -Djava.io.tmpdir=/opt/apache-tomcat/apache-tomcat-7.0.72/temp
4211 是jps命令自身的pid,
21991 是linux下面的一個tomcat的pid,其主類、傳遞的參數以及配置與上面相似。
jstat(JVM Statistics Monitoring Machine)是用於監視虛擬機各類運行狀態信息的工具。它能夠顯示本地或者遠程虛擬機進程中的類裝載、內存、垃圾收集、JID編譯等運行時數據,在沒有GUI的服務器上,對於定位虛擬機性能問題很是重要。
jstat命令格式爲:
jstat [ option vmid [interval [s|ms] [count] ] ]
對於命令格式中的VMID與LVMID須要特別說明一下:若是是本地虛擬機進程,VMID與LVMID是一致的,若是是遠程虛擬機進程,那VMID的格式應當以下:
[protocol:][//]lvmid[@hostname[:port]/servername]
參數interval和count表明查詢的間隔和次數,若是省略這兩個參數,說明只查詢一次。假設須要每250ms查詢一次pid爲 2204 程序的垃圾收集狀態,總共查詢20次,那麼命令應當是:
jstat -gc 2204 250 20
選項option表明着用戶但願查詢的虛擬機信息,分爲3類:類裝載、垃圾收集、運行期編譯情況,具體做用以下:
-class 監視類裝載、卸載數量、總空間以及類裝載所耗費的時間
-gc 監視java堆情況,包括Eden區、兩個suprivor區、老年代、永久代等的容量、已用空間、GC時間合計等信息(實際在hotspot虛擬機中,永久代不屬於堆內存,並且在JDK8已經被元空間MetaSpace所取代)
-gccapacity 監視內容與-gc基本相同,可是輸出主要關注的是Java堆各個區域使用的最大、最小空間
-gcutil 監視內容與-gc基本相同,但輸出主要關注已使用空間佔總空間的比例
-gccause 監視內容與-gc基本相同,可是會額外輸出致使上一致gc的緣由。
-gcnew 監視新生代GC情況
-gcnewcapacity 監視內容與-gcnew基本相同,可是輸出主要關注的是使用的最大、最小空間
-gcold 監視老年代GC情況
-gcoldcapacity 監視內容與-gcold基本相同,可是輸出主要關注的是使用的最大、最小空間
-gcpermcapacity 輸出永久代最大、最小空間
-compiler 輸出JIT編譯過的方法、耗時等信息
-printcompilation 輸出已經被JIT編譯的方法
例如本身windows下面的測試
C:\Users\Administrator>jstat -gcutil 2204 S0 S1 E O P YGC YGCT FGC FGCT GCT 0.00 0.00 33.52 54.34 55.99 15 0.322 1 0.282 0.604
實驗結果代表:這臺虛擬機的新生代Enen區(E表示Eden)使用了33.52%空間,兩個Suprivor區(SO和S1)都是空的,老年代Old(o表示Old)佔用了54.34%,永久代(Perm)佔用了55.99%。程序運行以愛共發生Minor GC(YGC表示Young GC)15次,總耗時0.322秒。發生FullGC(FGC)1次,FullGC總耗時0.282秒,全部GC耗時(GCT) 0.604秒。
下面是一些其餘測試:
C:\Users\Administrator>jstat -gccause 2204 S0 S1 E O P YGC YGCT FGC FGCT GCT LGCC GCC 0.00 0.00 33.52 54.34 55.99 15 0.322 1 0.282 0.604 Allocation Failure No GC C:\Users\Administrator>jstat -class 2204 Loaded Bytes Unloaded Bytes Time 7880 15537.3 0 0.0 13.07 C:\Users\Administrator>jstat -gc 2204 S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT 43520.0 44544.0 0.0 0.0 499200.0 172323.0 120320.0 65384.2 83456.0 46728.6 15 0.322 1 0.282 0.604 C:\Users\Administrator>jstat -compiler 2204 Compiled Failed Invalid Time FailedType FailedMethod 1504 1 0 17.19 1 org/apache/catalina/loader/WebappClassLoaderBase findResourceInternal C:\Users\Administrator>jstat -gccapacity 2204 NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC PGCMN PGCMX PGC PC YGC FGC 43008.0 686080.0 684544.0 43520.0 44544.0 499200.0 85504.0 1372160.0 120320.0 120320.0 21504.0 83968.0 83456.0 83456.0 15 1
本身在linux下面的測試:
[root@VM_0_12_centos ~]# jstat -gcutil 21991 S0 S1 E O P YGC YGCT FGC FGCT GCT 0.00 9.81 36.74 64.58 99.78 931 8.255 17 2.609 10.865 [root@VM_0_12_centos ~]# jstat -gccause 21991 S0 S1 E O P YGC YGCT FGC FGCT GCT LGCC GCC 0.00 9.81 38.73 64.58 99.78 931 8.255 17 2.609 10.865 Allocation Failure No GC [root@VM_0_12_centos ~]# jstat -class 21991 Loaded Bytes Unloaded Bytes Time 12028 24837.3 48 70.8 66.16 [root@VM_0_12_centos ~]# jstat -compiler 21991 Compiled Failed Invalid Time FailedType FailedMethod 2543 2 0 71.49 1 org/apache/jasper/xmlparser/ParserUtils convert
一些具體的參數解釋以下:
S0C:年輕代中第一個survivor(倖存區)的容量 (字節)
S1C:年輕代中第二個survivor(倖存區)的容量 (字節)
S0U:年輕代中第一個survivor(倖存區)目前已使用空間 (字節)
S1U:年輕代中第二個survivor(倖存區)目前已使用空間 (字節)
EC:年輕代中Eden(伊甸園)的容量 (字節)
EU:年輕代中Eden(伊甸園)目前已使用空間 (字節)
OC:Old代的容量 (字節)
OU:Old代目前已使用空間 (字節)
PC:Perm(持久代)的容量 (字節)
PU:Perm(持久代)目前已使用空間 (字節)
YGC:從應用程序啓動到採樣時年輕代中gc次數
YGCT:從應用程序啓動到採樣時年輕代中gc所用時間(s)
FGC:從應用程序啓動到採樣時old代(全gc)gc次數
FGCT:從應用程序啓動到採樣時old代(全gc)gc所用時間(s)
GCT:從應用程序啓動到採樣時gc用的總時間(s)
NGCMN:年輕代(young)中初始化(最小)的大小 (字節)
NGCMX:年輕代(young)的最大容量 (字節)
NGC:年輕代(young)中當前的容量 (字節)
OGCMN:old代中初始化(最小)的大小 (字節)
OGCMX:old代的最大容量 (字節)
OGC:old代當前新生成的容量 (字節)
PGCMN:perm代中初始化(最小)的大小 (字節)
PGCMX:perm代的最大容量 (字節)
PGC:perm代當前新生成的容量 (字節)
S0:年輕代中第一個survivor(倖存區)已使用的佔當前容量百分比
S1:年輕代中第二個survivor(倖存區)已使用的佔當前容量百分比
E:年輕代中Eden(伊甸園)已使用的佔當前容量百分比
O:old代已使用的佔當前容量百分比
P:perm代已使用的佔當前容量百分比
S0CMX:年輕代中第一個survivor(倖存區)的最大容量 (字節)
S1CMX :年輕代中第二個survivor(倖存區)的最大容量 (字節)
ECMX:年輕代中Eden(伊甸園)的最大容量 (字節)
DSS:當前須要survivor(倖存區)的容量 (字節)(Eden區已滿)
TT: 持有次數限制
MTT : 最大持有次數限制
jinfo(Configuration Info for Java)的做用是 實時查看和調整虛擬機的各項參數。使用jps -v 能夠查看虛擬器啓動時候顯示指定的參數列表,可是若是想查找未被顯示指定的參數的系統的默認值,除了去查閱資料,就只能使用jinfo的 -flag選項進行查詢了(若是隻限於JDK版本6以上,使用Java -XX:+PrintFlagsFinal 查看默認值也是一個很好的選擇),jinfo還可使用 -sysprops選項把虛擬機進程的System.getProperties()的內容打印出來,JDK1.6以後,jinfo在windows和linux平臺都提供,而且加入了運行期修改參數的能力,可使用 -flag [+|-] name 或者 -flag name=value修改一部分運行期可寫的虛擬機參數值。JDK1.6中,jinfo對於windows平臺功能仍然有較大限制,只提供了最基本的-flag選項。
jinfo的命令格式以下:
C:\Users\Administrator>jinfo -flag Usage: jinfo [option] <pid> (to connect to running process) jinfo [option] <executable <core> (to connect to a core file) jinfo [option] [server_id@]<remote server IP or hostname> (to connect to remote debug server) where <option> is one of: -flag <name> to print the value of the named VM flag -flag [+|-]<name> to enable or disable the named VM flag -flag <name>=<value> to set the named VM flag to the given value -flags to print VM flags -sysprops to print Java system properties <no option> to print both of the above -h | -help to print this help message
例如:
(1)查看一個JVM的配置信息,也就是System.getProperties能夠獲取的信息:
C:\Users\Administrator>jinfo 2084 Attaching to process ID 2084, please wait... Debugger attached successfully. Server compiler detected. JVM version is 24.80-b11 Java System Properties: java.vendor = Oracle Corporation osgi.bundles.defaultStartLevel = 4 org.eclipse.debug.ui.breakpoints.toggleFactoriesUsed = false org.osgi.supports.framework.extension = true sun.management.compiler = HotSpot 64-Bit Tiered Compilers eclipse.p2.profile = epp.package.jee os.name = Windows 8
...
或者
C:\Users\Administrator>jinfo -sysprops 2084 Attaching to process ID 2084, please wait... Debugger attached successfully. Server compiler detected. JVM version is 24.80-b11 java.vendor = Oracle Corporation osgi.bundles.defaultStartLevel = 4 org.eclipse.debug.ui.breakpoints.toggleFactoriesUsed = false org.osgi.supports.framework.extension = true sun.management.compiler = HotSpot 64-Bit Tiered Compilers eclipse.p2.profile = epp.package.jee os.name = Windows 8
...
(2)查看JVM的啓動參數信息
C:\Users\Administrator>jinfo -flags 2084 Attaching to process ID 2084, please wait... Debugger attached successfully. Server compiler detected. JVM version is 24.80-b11 -Dosgi.requiredJavaVersion=1.7 -Xms256m -Xmx1024m -Xloggc:gc.log -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Dsun.lang.ClassLoader.allowArraySyntax=true -XX:MaxPermSize=256m
(3)查看是否開啓了GC日誌的打印:
C:\Users\Administrator>jinfo -flag PrintGC 2084 -XX:+PrintGC C:\Users\Administrator>jinfo -flag PrintGCDetails 2084 -XX:+PrintGCDetails
(4)關閉GC打印功能
C:\Users\Administrator>jinfo -flag -PrintGC 2084 C:\Users\Administrator>jinfo -flag -PrintGCDetails 2084 C:\Users\Administrator>jinfo -flag PrintGC 2084 -XX:-PrintGC C:\Users\Administrator>jinfo -flag PrintGCDetails 2084 -XX:-PrintGCDetails
有一點必須注意:PrintGC必須開啓,只開啓PrintGCDetails、PrintGCTimeStamps不會輸出GC,必須PrintGC同時開啓
(5)查看啓動參數
C:\Users\Administrator>jinfo -flag MaxHeapSize 2084 -XX:MaxHeapSize=1073741824 C:\Users\Administrator>jinfo -flag PermSize 2084 -XX:PermSize=21757952
jmap(Memory map for java)命令用於生成堆轉儲快照(通常稱爲heapdump或dump文件),若是不使用jmap命令,想要獲取java堆轉儲快照,還有一些比較暴力的手段:好比說用 -XX:+HeapDumpOnOutOfMemoryError參數,可讓虛擬機在發生OOM異常以後自動生成dump文件,經過 -XX:+HeapDumpOnCtrlBreak參數則可使用 [Ctrl]+[Break]鍵讓虛擬機生成dump文件,又或者在linux下面經過 Kill -3 命令發送進程退出信號"嚇唬"一下虛擬機,也能拿到dump文件。
jmap的做用不只是爲了獲取dump文件,它還能夠查詢finalize執行隊列、Java堆和永久代的詳細信息,如空間使用率、當前使用的是哪一種收集器等。
和jinfo同樣,jmap有很多功能在windows平臺下都是受限的,除了生成dump文件的-dump選項和用於查看每一個類的實例、空間佔用的-histo選項在全部操做系統都提供以外,其他選項都只能在Linux/Solaris下使用。
jmap的命令格式:
C:\Users\Administrator>jmap Usage: jmap [option] <pid> (to connect to running process) jmap [option] <executable <core> (to connect to a core file) jmap [option] [server_id@]<remote server IP or hostname> (to connect to remote debug server) where <option> is one of: <none> to print same info as Solaris pmap -heap to print java heap summary -histo[:live] to print histogram of java object heap; if the "live" suboption is specified, only count live objects -permstat to print permanent generation statistics -finalizerinfo to print information on objects awaiting finalization -dump:<dump-options> to dump java heap in hprof binary format dump-options: live dump only live objects; if not specified, all objects in the heap are dumped. format=b binary format file=<file> dump heap to <file> Example: jmap -dump:live,format=b,file=heap.bin <pid> -F force. Use with -dump:<dump-options> <pid> or -histo to force a heap dump or histogram when <pid> does not respond. The "live" suboption is not supported in this mode. -h | -help to print this help message -J<flag> to pass <flag> directly to the runtime system
(1)windows下面的測試
C:\Users\Administrator>jmap -heap 2084 #查看堆內存 Attaching to process ID 2084, please wait... Debugger attached successfully. Server compiler detected. JVM version is 24.80-b11 using thread-local object allocation. Parallel GC with 4 thread(s) Heap Configuration: MinHeapFreeRatio = 0 MaxHeapFreeRatio = 100 MaxHeapSize = 1073741824 (1024.0MB) NewSize = 1310720 (1.25MB) MaxNewSize = 17592186044415 MB OldSize = 5439488 (5.1875MB) NewRatio = 2 SurvivorRatio = 8 PermSize = 21757952 (20.75MB) MaxPermSize = 268435456 (256.0MB) G1HeapRegionSize = 0 (0.0MB) Heap Usage: PS Young Generation Eden Space: capacity = 295698432 (282.0MB) used = 12552440 (11.970939636230469MB) free = 283145992 (270.02906036376953MB) 4.245014055400875% used From Space: capacity = 13107200 (12.5MB) used = 13080592 (12.474624633789062MB) free = 26608 (0.0253753662109375MB) 99.7969970703125% used To Space: capacity = 10485760 (10.0MB) used = 0 (0.0MB) free = 10485760 (10.0MB) 0.0% used PS Old Generation capacity = 541589504 (516.5MB) used = 211967328 (202.14779663085938MB) free = 329622176 (314.3522033691406MB) 39.13800515602311% used PS Perm Generation capacity = 166199296 (158.5MB) used = 166122072 (158.42635345458984MB) free = 77224 (0.07364654541015625MB) 99.95353530258035% used 44318 interned Strings occupying 4390312 bytes.
C:\Users\Administrator>jmap -histo:live 2084 >> tt.txt
打開文件查看結果:最後有3068個類 (咱們也能夠發現pring的單例模式,確實使用了CGLIB代理模式生成惟一的代理對象)
C:\Users\Administrator>jmap -dump:live,format=b,file=heap.bin 2204 Dumping heap to C:\Users\Administrator\heap.bin ... Heap dump file created
(2)linux下面的測試:
[root@VM_0_12_centos ~]# jmap -heap 21991 #查看內存JVM參數 Attaching to process ID 21991, please wait... Debugger attached successfully. Server compiler detected. JVM version is 24.80-b11 using thread-local object allocation. Mark Sweep Compact GC Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 482344960 (460.0MB) NewSize = 1310720 (1.25MB) MaxNewSize = 17592186044415 MB OldSize = 5439488 (5.1875MB) NewRatio = 2 SurvivorRatio = 8 PermSize = 21757952 (20.75MB) MaxPermSize = 85983232 (82.0MB) G1HeapRegionSize = 0 (0.0MB) Heap Usage: New Generation (Eden + 1 Survivor Space): capacity = 78053376 (74.4375MB) used = 12557464 (11.975730895996094MB) free = 65495912 (62.461769104003906MB) 16.088303470691645% used Eden Space: capacity = 69402624 (66.1875MB) used = 11711400 (11.168861389160156MB) free = 57691224 (55.018638610839844MB) 16.874578113934135% used From Space: capacity = 8650752 (8.25MB) used = 846064 (0.8068695068359375MB) free = 7804688 (7.4431304931640625MB) 9.780236446496213% used To Space: capacity = 8650752 (8.25MB) used = 0 (0.0MB) free = 8650752 (8.25MB) 0.0% used tenured generation: capacity = 173322240 (165.29296875MB) used = 111934032 (106.74861145019531MB) free = 61388208 (58.54435729980469MB) 64.58145936724566% used Perm Generation: capacity = 77332480 (73.75MB) used = 77163160 (73.5885238647461MB) free = 169320 (0.16147613525390625MB) 99.78104930813029% used 30082 interned Strings occupying 3502776 bytes. [root@VM_0_12_centos ~]# jmap -histo:live 21991 >> exam.info #查看存活對象信息,重定向到文件中 [root@VM_0_12_centos ~]# jmap -dump:live,format=b,file=heap.bin 21991 #查看堆轉儲快照信息 Dumping heap to /root/heap.bin ... Heap dump file created
jhat(JVM Heap Analysis Tool)命令與jmap搭配使用,來分析jmap生成的堆轉儲快照。jhat內置了一個小型的HTTP/HTML分析器,生成dump文件的分析結果以後,能夠在瀏覽器查看。通常也用不到這個工具,主要緣由有:一是通常不會在部署應用程序的服務器上直接生成dump文件,即便這樣作了,也會盡可能將dump文件複製到其餘機器進行分析,由於分析工做是一個耗時且消耗硬件資源的工做;二是此工具的分析功能相對比較簡陋,比較好的有Visual VM,以及專業用於分析dump文件的Eclipse Memory Analyzer等。
接下來用jhat分析上面jmap生成的dump快照信息:
C:\Users\Administrator>jhat heap.bin Reading from heap.bin... Dump file created Mon Dec 03 15:04:02 CST 2018 Snapshot read, resolving... Resolving 816411 objects... Chasing references, expect 163 dots................................................................................................................................................................... Eliminating duplicate references................................................................................................................................................................... Snapshot resolved. Started HTTP server on port 7000 Server is ready.
能夠看到上面在端口7000,創建了http監聽,輸入http://localhost:7000/ 便可查看分析信息
分析結果默認是以包爲單位分組顯示,分析內存泄漏問題主要會使用其中的"heap histogram"(與jmap -histo)功能同樣能夠查看類的統計信息與OQL頁籤的功能,前者能夠找到內存中總容量最大的對象,後者是標準的對象查詢語言,使用相似SQL的語法對內存中的對象進行查詢統計(這個參考深刻JVM虛擬機一書能夠方便使用)。
查看heap histogram
點一個類進去再次查看:(這裏也解釋了spring的cglib代理功能基於繼承方式實現)
再次點擊DepartmentServiceImpl查看:
jstack(Stack Trace For Java)命令用於生成虛擬機當前時刻的線程快照(通常成爲threaddump或者javacore文件)。線程快照就是當前虛擬機內每一條線程正在執行的方法堆棧的集合,生成線程快照的目的是爲了定位線程出現長時間停頓的緣由,如線程間死鎖、死循環、請求外部資源等待的時間過長等緣由。線程出現停頓的時候能夠經過jstack來查看各個線程的調用堆棧,就能夠知道響應的線程到底在後臺作什麼或者等待什麼資源。
jstack的命令格式以下:
C:\Users\Administrator>jstack Usage: jstack [-l] <pid> (to connect to running process) jstack -F [-m] [-l] <pid> (to connect to a hung process) jstack [-m] [-l] <executable> <core> (to connect to a core file) jstack [-m] [-l] [server_id@]<remote server IP or hostname> (to connect to a remote debug server) Options: -F to force a thread dump. Use when jstack <pid> does not respond (process is hung) -m to print both java and native frames (mixed mode) -l long listing. Prints additional information about locks -h or -help to print this help message
例如:
C:\Users\Administrator>jstack -l 2204
在JDK1.5中,java.lang.Thread類新增了一個getAllStackTraces()方法用於獲取虛擬機中全部線程的StackTraceElement對象。使用這個對象能夠經過簡單的幾行代碼就完成jstack的大部分功能,在實際項目中能夠用這個作管理界面,可隨時查看線程堆棧。以下代碼:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.util.Map"%> <html> <head> <title>服務器線程堆棧信息</title> </head> <body> <% for (Map.Entry<Thread, StackTraceElement[]> stackTrace : Thread.getAllStackTraces().entrySet()) { Thread thread = (Thread) stackTrace.getKey(); StackTraceElement[] stackTraceElements = stackTrace.getValue(); if (thread.equals(Thread.currentThread())) { continue; } out.print("\n 線程->" + thread.getName() + "\n"); for (StackTraceElement s : stackTraceElements) { out.print("\t" + s + "\n"); } } %> </body> </html>
補充:jstack也能夠用來檢測死鎖
一個死鎖程序:
package cn.xm.exam.test; public class test { public static void main(String[] args) { final Integer lock1 = 1; final Integer lock2 = 2; Runnable r1 = new Runnable() { @Override public void run() { synchronized (lock1) { try { System.out.println("lock1-----"); Thread.sleep(2 * 1000); synchronized (lock2) { System.out.println("lock1-----lock2"); } } catch (InterruptedException e) { } } } }; new Thread(r1).start(); Runnable r2 = new Runnable() { @Override public void run() { synchronized (lock2) { try { System.out.println("lock2-----"); Thread.sleep(2 * 1000); synchronized (lock1) { System.out.println("lock2-----lock1"); } } catch (InterruptedException e) { } } } }; new Thread(r2).start(); } }
jps+jstack檢測死鎖:
C:\Users\liqiang>jps 336164 342476 test 343376 Jps C:\Users\liqiang>jstack 342476 2018-12-10 21:19:47 Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.80-b11 mixed mode): "DestroyJavaVM" prio=6 tid=0x00000000026a5800 nid=0x53a04 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Thread-1" prio=6 tid=0x000000000e97e800 nid=0x53134 waiting for monitor entry [0x000000000ef7f000] java.lang.Thread.State: BLOCKED (on object monitor) at cn.xm.exam.test.test$2.run(test.java:33) - waiting to lock <0x00000007c0af8478> (a java.lang.Integer) - locked <0x00000007c0af8488> (a java.lang.Integer) at java.lang.Thread.run(Thread.java:745) "Thread-0" prio=6 tid=0x000000000e97d800 nid=0x53b40 waiting for monitor entry [0x000000000ee7f000] java.lang.Thread.State: BLOCKED (on object monitor) at cn.xm.exam.test.test$1.run(test.java:16) - waiting to lock <0x00000007c0af8488> (a java.lang.Integer) - locked <0x00000007c0af8478> (a java.lang.Integer) at java.lang.Thread.run(Thread.java:745) "Service Thread" daemon prio=6 tid=0x000000000d04b000 nid=0x4e590 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread1" daemon prio=10 tid=0x000000000d03a000 nid=0x53594 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread0" daemon prio=10 tid=0x000000000d035000 nid=0x52bd8 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Attach Listener" daemon prio=10 tid=0x000000000d034000 nid=0x52d64 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Signal Dispatcher" daemon prio=10 tid=0x000000000d030800 nid=0x531f0 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Finalizer" daemon prio=8 tid=0x000000000278c800 nid=0x53868 in Object.wait() [0x000000000e37f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000007c0904858> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135) - locked <0x00000007c0904858> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209) "Reference Handler" daemon prio=10 tid=0x0000000002784800 nid=0x53adc in Object.wait() [0x000000000e27f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000007c0904470> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:503) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133) - locked <0x00000007c0904470> (a java.lang.ref.Reference$Lock) "VM Thread" prio=10 tid=0x000000000cff3000 nid=0x53ad0 runnable "GC task thread#0 (ParallelGC)" prio=6 tid=0x00000000026bb000 nid=0x53b08 runnable "GC task thread#1 (ParallelGC)" prio=6 tid=0x00000000026bc800 nid=0x53ac4 runnable "GC task thread#2 (ParallelGC)" prio=6 tid=0x00000000026be800 nid=0x53368 runnable "GC task thread#3 (ParallelGC)" prio=6 tid=0x00000000026c0000 nid=0x53acc runnable "VM Periodic Task Thread" prio=10 tid=0x000000000d08e800 nid=0x539a4 waiting on condition JNI global references: 111 Found one Java-level deadlock: ============================= "Thread-1": waiting to lock monitor 0x000000000278c3b8 (object 0x00000007c0af8478, a java.lang.Integer), which is held by "Thread-0" "Thread-0": waiting to lock monitor 0x000000000278af18 (object 0x00000007c0af8488, a java.lang.Integer), which is held by "Thread-1" Java stack information for the threads listed above: =================================================== "Thread-1": at cn.xm.exam.test.test$2.run(test.java:33) - waiting to lock <0x00000007c0af8478> (a java.lang.Integer) - locked <0x00000007c0af8488> (a java.lang.Integer) at java.lang.Thread.run(Thread.java:745) "Thread-0": at cn.xm.exam.test.test$1.run(test.java:16) - waiting to lock <0x00000007c0af8488> (a java.lang.Integer) - locked <0x00000007c0af8478> (a java.lang.Integer) at java.lang.Thread.run(Thread.java:745) Found 1 deadlock.
JDK除了上面的大量的命令行工具,還提供了兩個可視化工具,JConsole和Visual VM。JConsole是JDL5纔有的,而Visual VM是JDK6的Update7中首次發佈的,如今已經成爲主流的多合一故障處理工具。
JConsole(Java Monitoring and management Console)是基於JMX的可視化監視、管理工具。它管理部分的功能是針對JMX MBean進行管理,因爲MBean可使用代碼、中間件服務器的管理控制檯或者全部符合JMX規範的軟件進行訪問。
雙擊Jdk/bin/jconsole.exe啓動便可。啓動以後會自動顯示本地的LVMID,至關於JPS功能,雙擊一個打開便可。
也可使用下面的遠程進程進行遠程鏈接。
概述頁籤顯示的是整個虛擬機運行時數據的概覽,其中包括"堆使用狀況"、"線程"、"類"、"CPU佔用率等",這些曲線圖是後面內存、線程、類頁籤的彙總。
內存頁籤至關於可視化的jstat命令。(在這裏也能夠看出永久代屬於非堆區)。也能夠看到垃圾收集器以及垃圾收集時間等信息。
線程頁籤至關於jstack命令,遇到線程停頓時能夠用這個命令進行分析。也能夠進行死鎖檢測。
下面模擬一個線程死鎖的線程檢測:(一個簡單的雙同步發生的線程死鎖的例子)
package cn.xm.exam.test; public class test { public static void main(String[] args) { final Integer lock1 = 1; final Integer lock2 = 2; Runnable r1 = new Runnable() { @Override public void run() { synchronized (lock1) { try { System.out.println("lock1-----"); Thread.sleep(2 * 1000); synchronized (lock2) { System.out.println("lock1-----lock2"); } } catch (InterruptedException e) { } } } }; new Thread(r1).start(); Runnable r2 = new Runnable() { @Override public void run() { synchronized (lock2) { try { System.out.println("lock2-----"); Thread.sleep(2 * 1000); synchronized (lock1) { System.out.println("lock2-----lock1"); } } catch (InterruptedException e) { } } } }; new Thread(r2).start(); } }
再次檢測死鎖查看線程死鎖信息:(能夠看到多處一個死鎖籤,能夠看到發生死鎖的當前線程所擁有的鎖以及等待的另外一個鎖被另外一個線程鎖所擁有)
1.啓動
位於jdk/bin/jvisualvm.exe,雙擊便可啓動,啓動也是會顯示JPS相似的功能,雙擊一個PID進去便可。
2.概述
能夠看到參數信息,以及一些配置信息。有jps -ml的功能。其系統屬性的頁籤相似於jinfo功能。也能夠看到JVM參數的設置信息。
3.監視頁籤查看概述信息
也能夠dump出堆轉儲快照。
執行堆dump以後能夠進行分析類以及實例信息,相似於jmap -histo的功能 (重要) 。並且堆dump也能夠另存爲文件。
會自動檢測死鎖。
咱們dump出快照查看信息:
總結: 至此完成了工具的研究,最經常使用的是jps -lm + jmap -heap pid + jmap -histo:live 。若是可使用可視化工具的話jvisualVM是不錯的選擇。
補充一些JVM中的知識,便於分析類以及其實例:
在Java中,任何類型都有class,包括基本數據類型與void。在Java中 [ 表明數組, [[ 表明二維數組。依次類推。
其餘的描述標識符以下:
B---基本數據類型byte
C---基本數據類型char
D---基本數據類型double
F---基本數據類型float
I---基本數據類型int
J---基本數據類型long
S---基本數據類型short
Z---基本數據類型boolean
V---特殊類型void
L---對象類型(也就是引用類型)。例如 Ljava/lang/Object.
須要注意的是八種基本數據類型也有 calss,並且其對應包裝類型有一個TYPE成員變量就是其基本數據類型。特殊類型void也有class。基本類型的數組與引用類型數組也都有class
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
例如:
System.out.println(int.class); System.out.println(Integer.class); System.out.println(Integer.TYPE); System.out.println(Integer[].class); System.out.println(int[].class); System.out.println(void.class);
結果:
int
class java.lang.Integer
int
class [Ljava.lang.Integer;
class [I
void
注意int不是對象,因此沒有getClass方法。只有int.class