1. 程式人生 > >[JVM]虛擬機器監控工具(命令列)

[JVM]虛擬機器監控工具(命令列)

1.jps (Java Virtual Machine Process Status Tool)  

    用來檢視基於HotSpot的JVM裡面中,所有具有訪問許可權的Java程序的具體狀態, 包括程序ID,程序啟動的路徑及啟動引數等等,與unix上的ps類似,只不過jps是用來顯示java程序,可以把jps理解為ps的一個子集。     jps [options] [hostid]     如果不指定hostid就預設為當前主機或伺服器;如果指定了hostid,它就會顯示指定hostid上面的java程序,不過這需要遠端服務上開啟了jstatd服務。     -q:忽略輸出的類名、Jar名以及傳遞給main方法的引數,只輸出pid。     -m:輸出傳遞給main方法的引數,如果是內嵌的JVM則輸出為null。     -l:輸出完全的包名,應用主類名,jar的完全路徑名     -v:輸出傳給jvm的引數     -V:輸出通過標記的檔案傳遞給JVM的引數(.hotspotrc檔案,或者是通過引數-XX:Flags=指定的檔案)。     -J 用於傳遞jvm選項到由javac呼叫的java載入器中,例如,“-J-Xms48m”將把啟動記憶體設定為48M,使用-J選項可以非常方便的向基於Java的開發的底層虛擬機器應用程式傳遞引數。     jps -mlv  

  1. 9680 org.jetbrains.idea.maven.server.RemoteMavenServer -Djava.awt.headless=true -Didea.version==2017.1.1 -Xmx768m -Didea.maven.embedder.version=3.2.5 -Dfile.encoding=GBK

  2. 2356 org.jetbrains.jps.cmdline.Launcher C:/Program Files/JetBrains/IntelliJ IDEA 2017.1.1/lib/openapi.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2017.1.1/lib/jgoodies-forms.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2017.1.1/lib/javac2.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2017.1.1/lib/idea_rt.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2017.1.1/lib/jna-platform.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2017.1.1/lib/netty-all-4.1.9.Final.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2017.1.1/lib/protobuf-2.5.0.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2017.1.1/lib/annotations.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2017.1.1/lib/trove4j.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2017.1.1/lib/nanoxml-2.2.3.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2017.1.1/lib/forms_rt.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2017.1.1/lib/jdom.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2017.1.1/lib/asm-all.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2017.1.1/lib/jps-model.jar;C:/Program Files/JetBra -Xmx700m -Djava.awt.headless=true -Djava.endorsed.dirs="" -Djdt.compiler.useSingleThread=true -Dcompile.parallel=false -Drebuild.on.dependency.change=true -Djava.net.preferIPv4Stack=true -Dio.netty.initialSeedUniquifier=-8384703316530083662 -Dfile.encoding=GBK -Djps.file.types.component.name=FileTypeManager -Duser.language=zh -Duser.country=CN -Didea.paths.selector=IntelliJIdea2017.1 -Didea.home.path=C:\Program Files\JetBrains\IntelliJ IDEA 2017.1.1 -Didea.config.path=C:\Users\vincent\.IntelliJIdea2017.1\config -Didea.plugins.path=C:\Users\vincent\.IntelliJIdea2017.1\config\plugins -Djps.log.dir=C:/Users/vincent/.IntelliJIdea2017.1/system/log/build-log -Djps.fallback.jdk.home=C:/Program Files/JetBrains/IntelliJ IDEA 2017.1.1/jre64 -Djps.fallback.jdk.version=1.8.0_112-release -Dio.netty.noUnsafe=true -Djava.io.tmpdir=C:/Users/vincent/.IntelliJIdea2017.1/system/compile-server/es-demo_7a0f3d0f/_temp_ -Djps.backward.ref.index.builder=true -Dkotlin.incremental.compilation.experimental=true -Dkotlin.daemon.enabled

  3. 4116  -Xms128m -Xmx750m -XX:ReservedCodeCacheSize=240m -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -ea -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -Djb.vmOptionsFile=C:\Program Files\JetBrains\IntelliJ IDEA 2017.1.1\bin\idea64.exe.vmoptions -Xbootclasspath/a:C:\Program Files\JetBrains\IntelliJ IDEA 2017.1.1\lib\boot.jar -Didea.jre.check=true -Didea.paths.selector=IntelliJIdea2017.1 -XX:ErrorFile=C:\Users\vincent\java_error_in_idea_%p.log -XX:HeapDumpPath=C:\Users\vincent\java_error_in_idea.hprof

  4. 16776 sun.tools.jps.Jps -mlv -Denv.class.path=.;D:\jdk\lib\dt.jar;D:\jdk\lib\tools.jar;  -Dapplication.home=D:\jdk -Xms8m

2. jstack    

    jstack主要用來檢視某個Java程序內的執行緒堆疊資訊。

    jstack [option] pid       jstack [option] executable core       jstack [option] [[email protected]]remote-hostname-or-ip     -l long listings,會打印出額外的鎖資訊,在發生死鎖時可以用<strong>jstack -l pid</strong>來觀察鎖持有情況       -m mixed mode,不僅會輸出Java堆疊資訊,還會輸出C/C++堆疊資訊(比如Native方法)       jstack可以定位到執行緒堆疊,根據堆疊資訊我們可以定位到具體程式碼,所以它在JVM效能調優中使用得非常多。下面我們來一個例項找出某個Java程序中最耗費CPU的Java執行緒並定位堆疊資訊,用到的命令有ps、top、printf、jstack、grep。   第一步: 先找出Java程序ID,伺服器上的Java應用名稱為wordcount.jar:

  1. [email protected]:/# ps -ef | grep mrf-center | grep -v grep

  2. 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(),我找了下我的程式碼,定位到下面的程式碼。

  1. // Idle wait

  2. getLog().info("Thread [" + getName() + "] is idle waiting...");

  3. schedulerThreadState = PollTaskSchedulerThreadState.IdleWaiting;

  4. long now = System.currentTimeMillis();

  5. long waitTime = now + getIdleWaitTime();

  6. long timeUntilContinue = waitTime - now;

  7. synchronized(sigLock) {

  8. try {

  9. if(!halted.get()) {

  10. sigLock.wait(timeUntilContinue);

  11. }

  12. }

  13. catch (InterruptedException ignore) {

  14. }

  15. }

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

3. jmap(Memory Map)和jhat(Java Heap Analysis Tool)

  jmap用來檢視堆記憶體使用狀況,一般結合jhat使用。     jmap語法格式如下:  

  1. jmap [option] pid

  2. jmap [option] executable core

  3. jmap [option] [[email protected]]remote-hostname-or-ip

 如果執行在64位JVM上,可能需要指定-J-d64命令選項引數。 (1) 列印程序的類載入器和類載入器載入的持久代物件資訊,輸出:類載入器名稱、物件是否存活(不可靠)、物件地址、父類載入器、已載入的類大小等資訊,如下圖:      jmap -permstat pid (2) 使用jmap -heap pid檢視程序堆記憶體使用情況,包括使用的GC演算法、堆配置引數和各代中堆記憶體使用情況。比如下面的例子:     jmap -heap pid  

  1. [[email protected] home]# jmap -heap 2860

  2. Attaching to process ID 2860, please wait...

  3. Debugger attached successfully.

  4. Server compiler detected.

  5. JVM version is 20.45-b01

  6. using thread-local object allocation.

  7. Mark Sweep Compact GC

  8. Heap Configuration:

  9. MinHeapFreeRatio = 40

  10. MaxHeapFreeRatio = 70

  11. MaxHeapSize = 257949696 (246.0MB)

  12. NewSize = 1310720 (1.25MB)

  13. MaxNewSize = 17592186044415 MB

  14. OldSize = 5439488 (5.1875MB)

  15. NewRatio = 2

  16. SurvivorRatio = 8

  17. PermSize = 21757952 (20.75MB)

  18. MaxPermSize = 85983232 (82.0MB)

  19. Heap Usage:

  20. New Generation (Eden + 1 Survivor Space):

  21. capacity = 12189696 (11.625MB)

  22. used = 6769392 (6.4557952880859375MB)

  23. free = 5420304 (5.1692047119140625MB)

  24. 55.53372290826613% used

  25. Eden Space:

  26. capacity = 10878976 (10.375MB)

  27. used = 6585608 (6.280525207519531MB)

  28. free = 4293368 (4.094474792480469MB)

  29. 60.53518272307982% used

  30. From Space:

  31. capacity = 1310720 (1.25MB)

  32. used = 183784 (0.17527008056640625MB)

  33. free = 1126936 (1.0747299194335938MB)

  34. 14.0216064453125% used

  35. To Space:

  36. capacity = 1310720 (1.25MB)

  37. used = 0 (0.0MB)

  38. free = 1310720 (1.25MB)

  39. 0.0% used

  40. tenured generation:

  41. capacity = 26619904 (25.38671875MB)

  42. used = 15785896 (15.054603576660156MB)

  43. free = 10834008 (10.332115173339844MB)

  44. 59.30110040967841% used

  45. Perm Generation:

  46. capacity = 33554432 (32.0MB)

  47. used = 33323352 (31.779624938964844MB)

  48. free = 231080 (0.22037506103515625MB)

  49. 99.31132793426514% used

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

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

  2. num #instances #bytes class name

  3. ----------------------------------------------

  4. 1: 38445 5597736 <constMethodKlass>

  5. 2: 38445 5237288 <methodKlass>

  6. 3: 3500 3749504 <constantPoolKlass>

  7. 4: 60858 3242600 <symbolKlass>

  8. 5: 3500 2715264 <instanceKlassKlass>

  9. 6: 2796 2131424 <constantPoolCacheKlass>

  10. 7: 5543 1317400 [I

  11. 8: 13714 1010768 [C

  12. 9: 4752 1003344 [B

  13. 10: 1225 639656 <methodDataKlass>

  14. 11: 14194 454208 java.lang.String

  15. 12: 3809 396136 java.lang.Class

  16. 13: 4979 311952 [S

  17. 14: 5598 287064 [[I

  18. 15: 3028 266464 java.lang.reflect.Method

  19. 16: 280 163520 <objArrayKlassKlass>

  20. 17: 4355 139360 java.util.HashMap$Entry

  21. 18: 1869 138568 [Ljava.util.HashMap$Entry;

  22. 19: 2443 97720 java.util.LinkedHashMap$Entry

  23. 20: 2072 82880 java.lang.ref.SoftReference

  24. 21: 1807 71528 [Ljava.lang.Object;

  25. 22: 2206 70592 java.lang.ref.WeakReference

  26. 23: 934 52304 java.util.LinkedHashMap

  27. 24: 871 48776 java.beans.MethodDescriptor

  28. 25: 1442 46144 java.util.concurrent.ConcurrentHashMap$HashEntry

  29. 26: 804 38592 java.util.HashMap

  30. 27: 948 37920 java.util.concurrent.ConcurrentHashMap$Segment

  31. 28: 1621 35696 [Ljava.lang.Class;

  32. 29: 1313 34880 [Ljava.lang.String;

  33. 30: 1396 33504 java.util.LinkedList$Entry

  34. 31: 462 33264 java.lang.reflect.Field

  35. 32: 1024 32768 java.util.Hashtable$Entry

  36. 33: 948 31440 [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;

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

  1. B byte

  2. C char

  3. D double

  4. F float

  5. I int

  6. J long

  7. Z boolean

  8. [ 陣列,如[I表示int[]

  9. [L+類名 其他物件

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

jmap -dump:format=b,file=dumpFileName

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

  1. [email protected]:/# jmap -dump:format=b,file=/tmp/dump.dat 21711

  2. Dumping heap to /tmp/dump.dat ...

  3. Heap dump file created

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

  1. [email protected]:/# jhat -port 9998 /tmp/dump.dat

  2. Reading from /tmp/dump.dat...

  3. Dump file created Tue Jan 28 17:46:14 CST 2014

  4. Snapshot read, resolving...

  5. Resolving 132207 objects...

  6. Chasing references, expect 26 dots..........................

  7. Eliminating duplicate references..........................

  8. Snapshot resolved.

  9. Started HTTP server on port 9998

  10. Server is ready.

 然後就可以在瀏覽器中輸入主機地址:9998查看了:  

4.jstat(JVM統計監測工具)

    看看各個區記憶體和GC的情況  

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

[[email protected] Desktop]# jstat -gc 2860 250 6  

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

5.jinfo

    jinfo是jdk自帶的命令,用來檢視jvm的配置引數。通常會先使用jps檢視java程序的id,然後使用jinfo檢視指定pid的jvm資訊          jinfo -flags process_id  

jps
4704 Launcher
9680 RemoteMavenServer
4116
13052 Jps
jinfo -flags 9680
  1. Debugger attached successfully.

  2. Server compiler detected.

  3. JVM version is 25.91-b15

  4. Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=268435456 -XX:MaxHeapSize=805306368 -XX:MaxNewSize=268435456 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=89128960 -XX:OldSize=179306496 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC

  5. Command line: -Djava.awt.headless=true -Didea.version==2017.1.1 -Xmx768m -Didea.maven.embedder.version=3.2.5 -Dfile.encoding=GBK

6.hprof(Heap/CPU Profiling Tool)

    hprof能夠展現CPU使用率,統計堆記憶體使用情況。     2SE中提供了一個簡單的命令列工具來對java程式的cpu和heap進行 profiling,叫做HPROF。HPROF實際上是JVM中的一個native的庫,它會在JVM啟動的時候通過命令列引數來動態載入,併成為 JVM程序的一部分。若要在java程序啟動的時候使用HPROF,使用者可以通過各種命令列引數型別來使用HPROF對java程序的heap或者 (和)cpu進行profiling的功能。HPROF產生的profiling資料可以是二進位制的,也可以是文字格式的。這些日誌可以用來跟蹤和分析 java程序的效能問題和瓶頸,解決記憶體使用上不優的地方或者程式實現上的不優之處。二進位制格式的日誌還可以被JVM中的HAT工具來進行瀏覽和分析,用 以觀察java程序的heap中各種型別和資料的情況。在J2SE 5.0以後的版本中,HPROF已經被併入到一個叫做Java Virtual Machine Tool Interface(JVM TI)中。  

  1. java -agentlib:hprof[=options] ToBeProfiledClass

  2. java -Xrunprof[:options] ToBeProfiledClass

  3. javac -J-agentlib:hprof[=options] ToBeProfiledClass

  1. Option Name and Value Description Default

  2. --------------------- ----------- -------

  3. heap=dump|sites|all heap profiling all

  4. cpu=samples|times|old CPU usage off

  5. monitor=y|n monitor contention n

  6. format=a|b text(txt) or binary output a

  7. file=<file> write data to file java.hprof[.txt]

  8. net=<host>:<port> send data over a socket off

  9. depth=<size> stack trace depth 4

  10. interval=<ms> sample interval in ms 10

  11. cutoff=<value> output cutoff point 0.0001

  12. lineno=y|n line number in traces? y

  13. thread=y|n thread in traces? n

  14. doe=y|n dump on exit? y

  15. msa=y|n Solaris micro state accounting n

  16. force=y|n force output to <file> y

  17. verbose=y|n print messages about dumps y

- Get sample cpu information every 20 millisec, with a stack depth of 3:           java -agentlib:hprof=cpu=samples,interval=20,depth=3 classname       - Get heap usage information based on the allocation sites:           java -agentlib:hprof=heap=sites classname        上面每隔20毫秒取樣CPU消耗資訊,堆疊深度為3,生成的profile檔名稱是java.hprof.txt,在當前目錄。        預設情況下,java程序profiling的資訊(sites和dump)都會被 寫入到一個叫做java.hprof.txt的檔案中。大多數情況下,該檔案中都會對每個trace,threads,objects包含一個ID,每一 個ID代表一個不同的觀察物件。通常,traces會從300000開始。 預設,force=y,會將所有的資訊全部輸出到output檔案中,所以如果含有 多個JVMs都採用的HRPOF enable的方式執行,最好將force=n,這樣能夠將單獨的JVM的profiling資訊輸出到不同的指定檔案。 interval選項只在 cpu=samples的情況下生效,表示每隔多少毫秒對java程序的cpu使用情況進行一次採集。 msa選項僅僅在Solaris系統下才有效, 表示會使用Solaris下的Micro State Accounting功能