1. 程式人生 > >jdk原始碼解析(五)——虛擬機器效能監控與故障處理工具

jdk原始碼解析(五)——虛擬機器效能監控與故障處理工具

前面有一定的瞭解jvm、這裡就瞭解一下怎麼檢視虛擬機器,也就是對jvm的一個監控。

這裡主要講解jvm的相關工具以及使用:

1定義問題的思路

給一個系統定位問題的時候,知識,經驗是關鍵基礎,資料是依據,工具是運用知識處理資料的手段。這裡說的資料包括:執行日誌,異常堆疊,GC日誌,執行緒快照,堆轉儲快照等;

2 jvm工具之jdk的命令列工具

jdk 的bin 目錄是jdk的工具目錄,這些命令列工具大多數是 jdk/lib/tools.jar 類庫的一層薄包裝而已,它們主要的功能程式碼是在 tools 類庫中實現的;

介紹一下Sun JDK 監控和故障處理工具如下列表

一下就介紹一下jdk自帶的這6個命令列工具:

2.1 jps 虛擬機器程序狀況工具(jps==jvm process status tool)

它可以列出正在執行的虛擬機器程序,並顯示虛擬機器執行主類名稱以及這些程序的本地虛擬機器唯一ID;

jps用來檢視基於HotSpot的JVM裡面中,所有具有訪問許可權的Java程序的具體狀態, 包括程序ID,程序啟動的路徑及啟動引數等等,與unix上的ps類似,只不過jps是用來顯示java程序,可以把jps理解為ps的一個子集。 使用jps時,如果沒有指定hostid,它只會顯示本地環境中所有的Java程序;如果指定了hostid,它就會顯示指定hostid上面的java程序,不過這需要遠端服務上開啟了jstatd服務,可以參看前面的jstatd章節來啟動jstad服務。

命令格式 :jps [ options ] [ hostid ] 

引數說明 :

-q 忽略輸出的類名、Jar名以及傳遞給main方法的引數,只輸出pid。

-m 輸出傳遞給main方法的引數,如果是內嵌的JVM則輸出為null。

-l 輸出應用程式主類的完整包名,或者是應用程式JAR檔案的完整路徑。

-v 輸出傳給JVM的引數。

-V 輸出通過標記的檔案傳遞給JVM的引數(.hotspotrc檔案,或者是通過引數-XX:Flags=<filename>指定的檔案)。

-J 用於傳遞jvm選項到由javac呼叫的java載入器中,例如,“-J-Xms48m”將把啟動記憶體設定為48M,使用-J選項可以非常方便的向基於Java的開發的底層虛擬機器應用程式傳遞引數。下面樣例均在linux的jdk1.7下測試。

使用樣例:

[[email protected] ~]# jps   2897 Bootstrap   22558 Jps   [[email protected] ~]# jps -l   2897 org.apache.catalina.startup.Bootstrap   22568 sun.tools.jps.Jps   [[email protected] ~]# jps -v   2897 Bootstrap -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/local/tomcat/endorsed -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp   22578 Jps -Denv.class.path=/usr/java/jdk1.7.0/lib -Dapplication.home=/usr/java/jdk1.7.0 -Xms8m

2.2 jstat:虛擬機器統計資訊監視工具(jstat==jvm statistics monitoring tool) 用於監視虛擬機器各種執行狀態資訊的命令列工具。他可以顯示本地或者遠端虛擬機器程序中的類裝載,記憶體,垃圾收集,JIT編譯等執行資料,在沒有GUI的時候,它是執行期定位虛擬機器效能問題的首選工具; Jstat用於監控基於HotSpot的JVM,對其堆的使用情況進行實時的命令列的統計,使用jstat我們可以對指定的JVM做如下監控:

- 類的載入及解除安裝情況

- 檢視新生代、老生代及持久代的容量及使用情況

- 檢視新生代、老生代及持久代的垃圾收集情況,包括垃圾回收的次數及垃圾回收所佔用的時間

- 檢視新生代中Eden區及Survior區中容量及分配情況等

jstat工具特別強大,它有眾多的可選項,通過提供多種不同的監控維度,使我們可以從不同的維度來了解到當前JVM堆的使用情況。詳細檢視堆內各個部分的使用量,使用的時候必須加上待統計的Java程序號,可選的不同維度引數以及可選的統計頻率引數。

命令格式:jstat [ option vmid [interval] [s|ms] [count]] 對於命令格式中的 VMID和 LVMID。

如過是本地虛擬機器程序,VMID和LVMID是一致的,

如果是遠端虛擬機器,那VMID的格式應當是:[protocol:] [//] lvmid[@hostname[:port]rvername]. 

引數interval 和count分別表示查詢的間隔和次數,如果省略這兩個引數,說明只查詢一次。 如需要每250ms 查詢一次程序 2764 垃圾收集狀況,一共查詢20次,命名應該是: jstat -gc 2764 250 20

選項option代表著使用者希望查詢的虛擬機器資訊,主要分為三類:類裝載,垃圾收集、執行期編譯狀況、列表如下。

本地jstal使用案例:

注意:使用-gc會更加詳細,只是因為整齊使用了gcutil。

介紹查詢結果:

S0、S1 代表兩個Survivor區(Survivor0和Survivor1);

E 代表 新生代的Eden 區;

O(Old)代表老年代;

P(Permanent)代表永久代;

YGC(Young GC)代表Minor GC;

YGCT代表Minor GC耗時;

FGC(Full GC)代表Full GC耗時;

GCT代表Minor & Full GC共計耗時。

Java 堆分為新生代和老年代,新生代一般劃分為三塊區域,Eden + From Survivor + To Survivor,Eden 和 Survivor 的記憶體比為8:1,每次只使用一個Eden 和一個 Survivor 區域,另一個 Survivor 用於複製收集演算法回收記憶體。

下面的 86.19 是指使用了該區的多少空間百分之多少的空間。

使用gc的情況:

詳細介紹:

其他以gc開始的結果列跟gc選項結果列基本一樣,這裡不一一列舉了。

2.3 jinfo:java配置資訊工具

jinfo可以輸出並修改執行時的java 程序的opts。用處比較簡單,用於輸出JAVA系統引數及命令列引數。

jinfo的作用(function):  1>實時地檢視和調整虛擬機器各項引數。使用jps命令的-v 引數可以檢視jvm啟動時顯式指定的引數列表,但如果想知道未被顯式指定的引數的系統預設值,就只能使用 jinfo的-flag 選項進行查詢了; 2>jinfo還可以使用 -sysprops 選項把jvm 程序的 System.getProperties()的內容打印出來; 3>jinfo加入了執行期修改引數的能力,可以使用 -flag[+|-] name 或 -flag name=value 修改一部分執行期可寫的jvm 引數值;(jinfo 在 windows平臺的功能有較大限制,只提供了最基本的-flag選項) 命令格式: jinfo [option] pid 使用樣例:jinfo [option] pid //pid 通過 jps 來檢視

在linux下使用:

[[email protected] ~]# jinfo  -flag  MaxNewSize  2897   -XX:MaxNewSize=18446744073709486080

例如在win下的檢視:

F:\Java\jdk\jdk1.7.0_60\bin>jinfo 25592 Attaching to process ID 25592, please wait... Debugger attached successfully. Server compiler detected. JVM version is 24.60-b09 Java System Properties:   java.vendor = Oracle Corporation sun.java.launcher = SUN_STANDARD catalina.base = C:\Users\mch\.IntelliJIdea2017.1\system\tomcat\Unnamed_hy_logistics sun.management.compiler = HotSpot 64-Bit Tiered Compilers catalina.useNaming = true os.name = Windows 8.1 sun.boot.class.path = F:\Java\jdk\jdk1.7.0_60\jre\lib\resources.jar; com.sun.management.jmxremote =java.vm.specification.vendor = Oracle Corporation java.runtime.version = 1.7.0_60-b19 user.name = mch ...省略一大部分 java.vm.name = Java HotSpot(TM) 64-Bit Server VM file.encoding = GBK java.specification.version = 1.7   VM Flags: ...省略一大部分

2.4  jmap:java記憶體映像工具(memory map for java):

jmap用於生成堆轉儲快照(一般稱為heapdump或者dump檔案)。當然也可其他方法比如加引數-XX:+HeapDumpOnOutOfMemoryError引數,在虛擬機器OOM異常的之後自動生成dump檔案,也可以通過-XX:+HeapDumpOnCtrlBreak引數則可以使用Ctrl+Break鍵讓虛擬機器生成dump檔案。在前文測試中就有生成。dump檔案生成後可藉助jha、MAT( Eclipse Memory Analyzer tool)、IBM HeapAnalyzer來對dump分析。jmap不僅能獲取dump還可以查詢finalize執行佇列,java堆和永久代詳細資訊,空間使用率,當前用的是什麼收集器等。

jmap的作用並不僅僅是為了獲取dump檔案,它還可以查詢 finalize 執行佇列,java堆和永久代的詳細資訊;

命令格式:jmap [ option ] pid

option的合法值和具體含義如下表:

使用案例:

F:\Java\jdk\jdk1.7.0_60\bin>jps -l 15692 sun.tools.jps.Jps 25592 org.apache.catalina.startup.Bootstrap 6276 org.jetbrains.jps.cmdline.Launcher 3976   F:\Java\jdk\jdk1.7.0_60\bin>jmap -dump:format=b,file=eclipse.bin 25592 Dumping heap to F:\Java\jdk\jdk1.7.0_60\bin\eclipse.bin ... Heap dump file created   F:\Java\jdk\jdk1.7.0_60\bin>

2.5 jhat:虛擬機器堆轉儲快照分析工具 jhat是sun提供的dump分析工具,上面講過分析dump的工具還有MAT( Eclipse Memory Analyzer tool)、IBM HeapAnalyzer等,一般這個命令不太用到,是因為分析dump是個既耗時又耗機器資源的過程,第二個原因是這個工具比較簡陋,沒有MAT( Eclipse Memory Analyzer tool)、IBM HeapAnalyzer這些專業和強大。 命令格式:jhat file 使用樣例:

F:\Java\jdk\jdk1.7.0_60\bin>jmap -dump:format=b,file=eclipse.bin 25592 Dumping heap to F:\Java\jdk\jdk1.7.0_60\bin\eclipse.bin ... Heap dump file created 匯出快照完成、之後開始==解析快照: F:\Java\jdk\jdk1.7.0_60\bin>jhat eclipse.bin Reading from eclipse.bin... Dump file created Sat Oct 14 15:04:41 CST 2017 Snapshot read, resolving... Resolving 555500 objects... WARNING:  Failed to resolve object id 0x73e54f1e8 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54f1e8 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54f1e8 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54f1e8 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54f1e8 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54f1e8 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54f1e8 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54f1e8 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54f1e8 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54f1e8 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54e088 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54e088 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54e088 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54e088 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54e088 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54e088 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54e088 for field constantPoolOop (sig nature L) WARNING:  Failed to resolve object id 0x73e54e088 for field constantPoolOop (sig nature L) Chasing references, expect 111 dots............................................. .................................................................. Eliminating duplicate references................................................ ............................................................... Snapshot resolved. Started HTTP server on port 7000 Server is ready.

載在瀏覽器中輸入localhost:7000檢視結果(我是沒看懂哈哈)ctrl+c結束解析

注意:如果有其它工具可以分析,否則不建議使用jhat。首先,一般不會直接在生產環境直接分析dump檔案,因為分析dump檔案是一件耗時耗資源的事情,條件允許的話首選圖形分析工具(後面會介紹);其次是jhat的分析功能過於簡陋。 2.6 jstack:Java堆疊跟蹤工具

jstack(Stack Trace for Java)命令用於生產虛擬機器當前時刻的執行緒快照(一般稱為threaddump或者javacore檔案)。執行緒快照就是當虛擬機器內每一條執行緒正在執行的方法堆疊集合,生產執行緒快照的主要目的是定位執行緒出現長時間停頓的原因,如執行緒間死鎖、死迴圈、請求外部資源導致長時間等待等都是導致執行緒長時間停頓的常見原因。執行緒出現停頓的時候通過jstack來檢視各個執行緒的呼叫堆疊,就可以知道沒有響應的執行緒到底在後臺做些什麼事情,或者等待著什麼資源。

jstack命令格式:jstack [option] vmid

option選擇的合法值域具有含有請看下錶:

jstack執行樣例:

F:\Java\jdk\jdk1.7.0_60\bin>jstack -l 25592 Full thread dump Java HotSpot(TM) Server VM (20.45-b01 mixed mode): "Attach Listener" daemon prio=10 tid=0x0852b000 nid=0x1103 waiting on condition [0x00000000]    java.lang.Thread.State: RUNNABLE      Locked ownable synchronizers:         - None ...... ...... ...... "main" prio=10 tid=0x08058400 nid=0xf06 runnable [0xf6940000]    java.lang.Thread.State: RUNNABLE         at java.net.PlainSocketImpl.socketAccept(Native Method)         at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408)         - locked <0xea12b248> (a java.net.SocksSocketImpl)         at java.net.ServerSocket.implAccept(ServerSocket.java:462)         at java.net.ServerSocket.accept(ServerSocket.java:430)         at org.apache.catalina.core.StandardServer.await(StandardServer.java:430)         at org.apache.catalina.startup.Catalina.await(Catalina.java:676)         at org.apache.catalina.startup.Catalina.start(Catalina.java:628)         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)         at 

...省略一大部分 2.7 HSDIS:JIT生成程式碼反彙編 由於本人沒有學習過彙編,所以在此章節部分的彙編內容看不懂,所以在這裡也只簡單介紹一下這個虛擬機器外掛的大概使用,後續本人學習了組合語言後有機會再寫相關的學習資料。 HSDIS是一個Sun官方推薦的HotSpot虛擬機器JIT編譯程式碼的反彙編外掛。在這先插兩句對JIT的簡單描述,JIT是講.class位元組碼翻譯成本機的機器程式碼(就是0和1),至於為什麼這麼做,肯定是提高效率,更多JIT知識可自行學習。 而HSDIS就是把這些被JIT翻譯過的機器碼(0和1)反編譯為彙編(面向IT人員的開發語言)。為什麼要無端端把機器語言翻譯會開發人員看得懂的組合語言,是因為當我們需要檢查程式效能的時候,希望更能接近計算機語言的本質去分析,由於彙編是直接面向硬體的,而機器語言我們又看不懂,所以最接近本質的還是組合語言。當然,我們可以基於位元組碼(.class)層面上進行分析,但隨著技術的發展,這些位元組碼指令的執行過程等細節與虛擬機器規範所描述的相差越來越遠,就是位元組碼的行為跟機器碼的行為有可能差異很大。所以通過組合語言分析可以更接近計算機語言的本質。 這個HSDIS JIT反彙編外掛包含在HotSpot虛擬機器的原始碼之中,但沒有提供編譯後的程式。在Project Kenai的網站也可以下載到單獨的原始碼。它的作用是讓HotSpot的-XX:PrintAssembly指令呼叫它來把動態生成的原生代碼還原為彙編程式碼輸出,同時還生成了大量有價值的註釋,這樣我們就可以通過輸出程式碼來分析問題。讀者可以根據自己的作業系統和CPU型別從Project Kenai的網站上下載編譯好的外掛,直接放到JDK_HOME/jre/bin/client和JDK_HOME/jre/bin/server目錄中即可。如果沒有找到所需作業系統的成品,那就得自己使用原始碼編譯一下。 3 jvm工具之jdk的視覺化工具

JDK中除了提供大量的命令列工具外,還有兩個功能強大的視覺化工具:JConsole和VisualVM,這兩個工具是JDK的正式成員。

3.1 JConsole:Java監視與管理控制檯

JConsole(Java Monitoring and Management Console)是一種基於JMX的視覺化監視、管理工具。它管理部分的功能是針對JMX Mbean進行管理。

知識擴充套件:JMX(Java Management Extensions)即ava管理擴充套件,MBean(managed beans)即被管理的Beans。一個MBean是一個被管理的Java物件,有點類似於JavaBean,一個裝置、一個應用或者任何資源都可以被表示為MBean,MBean會暴露一個介面對外,這個介面可以讀取或者寫入一些物件中的屬性。

啟動: 通過JDK_HOME/bin目錄下的“jconsole.exe”啟動JConsole後,講自動搜尋出本機執行的所有虛擬機器程序,不需要使用者自己再用JPS來查詢了。也可以使用下面的“遠端程序”功能來連線遠端伺服器,對遠端虛擬機器進行監控,若連線遠端虛擬機器,需要開啟JMX服務才能連線。如下圖所示:

下圖為進入JConsole的主頁:

概述”頁籤顯示的是整個虛擬機器主要執行資料的概覽,其中包括“堆記憶體使用情況”、“執行緒”、“類”、“CPU使用情況”4種資訊的曲線圖,這些曲線圖是後面“記憶體”、“執行緒”、“類”頁籤的資訊彙總。其它詳細的頁籤都不加以說明,自行學習吧,或者後期有充足的時間在詳解一下。

3.2 VisualVM:多合一故障處理工具

VisualVM(ALL-in-One Java Troubleshooting Tool)是到目前為止隨JDK釋出的功能最強大的執行監控和故障處理程式,並且可以預見在未來的一段時間內都是官方主力發展的虛擬機器故障處理工具。VisuaVM是基於NetBean平臺開發的,因此它一開始就具備了外掛擴充套件功能的特性,通過外掛擴充套件支援,VisualVM幾乎可以做到所欲命令列工具的功能和其它Plugins的無限可能性。

作用(functions) 1)顯示虛擬機器程序以及程序的配置,環境資訊(jps,jinfo); 2)監視應用程式的CPU, GC, 堆, 方法區以及執行緒的資訊(jstat、jstack); 3)dump 以及分析堆轉儲快照(jmap,jhat); 4)方法級的程式執行效能分析,找出被呼叫最多,執行時間最長的方法; 5)離執行緒序快照,收集程式的執行時配置,執行緒dump,記憶體dump 等資訊建立一個快照,可以將快照發送開發者處進行bug 反饋; 6)其他plugins 的無限可能性;(在對應用程式進行檢測時,還需要載入相應的外掛);

下圖為進入VisualVM的主頁:

VisualVM 主要特性的相容性列表:

首次啟動VisualVM後,讀者先不必著急找應用程式進行監控,因為現在VisualVM還沒有載入任何外掛,雖然基本的監控、執行緒面板的功能主程式都以預設外掛的形式提供了,但是不給VisualVM裝任何擴充套件外掛,就相當於放棄了它最精華的功能,和沒有安裝任何應用軟體的作業系統差不多。

外掛可以進行手工安裝,在相關網站上下載*.nbm包後,點選“工具—外掛—已下載”選單,然後在彈出的對話方塊中指定nbm包枯井變可以進行安裝,外掛安裝後存放在JDK_HOME/lib/visualvm/visualvm中。當然同樣可以在有網路連線的環境下選擇自動安裝,點選“工具—外掛—可用外掛”彈出如下圖所示的外掛頁籤中選擇合適的外掛安裝即可。

從VisualVM主頁的左選單欄可以看到,顯示的虛擬機器程序跟JConsole顯示的是一樣的,還有一個遠端虛擬機器程序。當我點選進入一個虛擬機器程序後的程序主頁如以下所示(不同版本可以會有所差異):

虛擬機器程序主頁包含了“概述”、“監視”、“抽樣器”、“Visual GC”頁籤,其中“Visual GC”是我自己安裝的外掛,更詳細的VisualVM使用說明就不多說了。後期學習在繼續詳細解釋。

4、總結:

jdk提供的vm故障處理工具都比較實用,常用的jps,jstat,jmap,jstack以及視覺化工具visualvm,當然根據個人實際實用情況,可能還選用第三方的工具進行dump分析,如eclipse的MAT(Memory Analyzer Tool)等。靈活實用這些工具,可以給處理問題帶來很大的便利。

最終:要知道出現什麼問題了考慮使用什麼工具。其它的就看你的經驗吧。 ---------------------