深入理解JAVA虚拟机 虚拟机性能监控和故障处理工具
jre的bin目錄下的工具,都非常小。它都是tools.jar下面的代碼的一層封裝而已。tools.jar不是java標準,是Hotspot實現的。
| 名稱???? | 作用 |
| jps | JVM Process Status Tool,現實指定系統內所有的HotSpot虛擬機進程? |
| jstat | JVM Statistics Monitoring Tool,用于收集Hotspot虛擬機各個方面的運行參數? |
| jinfo | Configuration Info for Java,現實虛擬機配置信息 |
| jmap | Memory map for java,生成虛擬機的內存轉儲快照 |
| jhat | JVM heap Dunp Browser,用于分析heapdump文件,他會建立一個HTTP/HTML服務,讓用戶可通過瀏覽器查看? |
| jstack | Stack Track for java ,顯示虛擬機線程快照 |
jps
jps用來查看基于HotSpot的JVM里面中,所有具有訪問權限的Java進程的具體狀態, 包括進程ID,進程啟動的路徑及啟動參數等等,與unix上的ps類似,只不過jps是用來顯示java進程,可以把jps理解為ps的一個子集。?
主要參數說明 :
-q 忽略輸出的類名、Jar名以及傳遞給main方法的參數,只輸出pid。
-m 輸出傳遞給main方法的參數,如果是內嵌的JVM則輸出為null。
-l 輸出應用程序主類的完整包名,或者是應用程序JAR文件的完整路徑。
-v 輸出傳給JVM的參數。
jstat
Jstat用于監控基于HotSpot的JVM,對其堆的使用情況進行實時的命令行的統計,使用jstat我們可以對指定的JVM做如下監控:
- 類的加載及卸載情況
- 查看新生代、老生代及持久代的容量及使用情況
- 查看新生代、老生代及持久代的垃圾收集情況,包括垃圾回收的次數及垃圾回收所占用的時間
- 查看新生代中Eden區及Survior區中容量及分配情況等
jstat工具特別強大,它有眾多的可選項,通過提供多種不同的監控維度,使我們可以從不同的維度來了解到當前JVM堆的使用情況。詳細查看堆內各個部分的使用量,使用的時候必須加上待統計的Java進程號,可選的不同維度參數以及可選的統計頻率參數。
命令格式:
jstat [ option vmid [interval][s|ms][count]]
option 參數如下面表格
Option Displays...
| class | 用于查看類加載情況的統計 |
| compiler | 用于查看HotSpot中即時編譯器編譯情況的統計 |
| gc | 用于查看JVM中堆的垃圾收集情況的統計 |
| gccapacity | 用于查看新生代、老生代及持久代的存儲容量情況 |
| gccause | 用于查看垃圾收集的統計情況(這個和-gcutil選項一樣),如果有發生垃圾收集,它還會顯示最后一次及當前正在發生垃圾收集的原因。 |
| gcnew | 用于查看新生代垃圾收集的情況 |
| gcnewcapacity | 用于查看新生代的存儲容量情況 |
| gcold | 用于查看老生代及持久代發生GC的情況 |
| gcoldcapacity | 用于查看老生代的容量 |
| gcpermcapacity | 用于查看持久代的容量 |
| gcutil | 用于查看新生代、老生代及持代垃圾收集的情況 |
| printcompilation | HotSpot編譯方法的統計 |
interval 和count 代表查詢次數和間隔。
列說明:
| S0C | 新生代中Survivor space中S0當前容量的大小(KB) |
| S1C | 新生代中Survivor space中S1當前容量的大小(KB) |
| S0U | 新生代中Survivor space中S0容量使用的大小(KB) |
| S1U | 新生代中Survivor space中S1容量使用的大小(KB) |
| EC | Eden space當前容量的大小(KB) |
| EU | Eden space容量使用的大小(KB) |
| OC | Old space當前容量的大小(KB) |
| OU | Old space使用容量的大小(KB) |
| PC | Permanent space當前容量的大小(KB) |
| PU | Permanent space使用容量的大小(KB) |
| YGC | 從應用程序啟動到采樣時發生 Young GC 的次數 |
| YGCT | 從應用程序啟動到采樣時 Young GC 所用的時間(秒) |
| FGC | 從應用程序啟動到采樣時發生 Full GC 的次數 |
| FGCT | 從應用程序啟動到采樣時 Full GC 所用的時間(秒) |
| GCT | T從應用程序啟動到采樣時用于垃圾回收的總時間(單位秒),它的值等于YGC+FGC |
jinfo
jinfo可以輸出并修改運行時的java 進程的opts。用處比較簡單,用于輸出JAVA系統參數及命令行參數。
jmap
jmap用于生成堆轉儲快照(一般稱為heapdump或者dump文件)。當然也可其他方法比如加參數-XX:+HeapDumpOnOutOfMemoryError參數,在虛擬機OOM異常的之后自動生成dump文件,也可以通過-XX:+HeapDumpOnCtrlBreak參數則可以使用Ctrl+Break鍵讓虛擬機生成dump文件。
參數說明:
-dump:[live,]format=b,file=<filename> 使用hprof二進制形式,輸出jvm的heap內容到文件=. live子選項是可選的,假如指定live選項,那么只輸出活的對象到文件.
-finalizerinfo 打印正等候回收的對象的信息.
-heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情況.
-histo[:live] 打印每個class的實例數目,內存占用,類全名信息. VM的內部類名字開頭會加上前綴"*". 如果live子參數加上后,只統計活的對象數量.
-permstat 打印classload和jvm heap長久層的信息. 包含每個classloader的名字,活潑性,地址,父classloader和加載的class數量. 另外,內部String的數量和占用內存數也會打印出來.
-F 強迫.在pid沒有相應的時候使用-dump或者-histo參數. 在這個模式下,live子參數無效.
jhat
jhat是sun提供的dump分析工具,上面講過分析dump的工具還有MAT(?Eclipse Memory Analyzer tool)、IBM HeapAnalyzer等,一般這個命令不太用到,是因為分析dump是個既耗時又耗機器資源的過程,第二個原因是這個工具比較簡陋,沒有MAT(?Eclipse Memory Analyzer tool)、IBM HeapAnalyzer這些專業和強大。
jstack
jstack用于打印出給定的java進程ID或core file或遠程調試服務的Java堆棧信息,如果是在64位機器上,需要指定選項"-J-d64"
可以查看線程當前的調用堆棧,線程狀態,鎖持有情況:
JDK可視化工具
jconsole
JConsole是一個基于JMX的GUI工具,用于連接正在運行的JVM,不過此JVM需要使用可管理的模式啟動。如果要把一個應用以可管理的形式啟動,可以在啟動是設置com.sun.management.jmxremote。
設置參數:
調用命令:
打開了可視化界面如下:
注意這里有一個檢測死鎖的功能。
jvisualVM
JDK自帶的JAVA性能分析工具。它已經在你的JDK bin目錄里了,只要你使用的是JDK1.6 Update7之后的版本。
jvisualVM所謂多合一虛擬機故障處理工具,有強大的插件擴展功能,通過安裝插件擴展支持,jvisualVM可以做到:
a、顯示虛擬機進程及進程的配置和環境信息(jps,jinfo);
b、監視應用程序CPU、GC、堆、方法區及線程的信息(jstat、jstack);
c、dump及分析堆轉儲快照(jmap、jhat);
d、方法級的程序性能分析,找出調用最多,運行時間最長的方法;
安裝
只要安裝JDK即可,運行jvisualvm.exe?,選擇【工具】——【插件】——【可用插件】(自帶的有幾個主要插件,不過jvisualvm提供了直接從網上檢查更新并下載其他插件)
·
如果版本比較老,那么還是連接的sun的插件重心,需要修改,在https://visualvm.github.io/pluginscenters.html 地址下,找到對應的jdk版本,將對應的.xml.gz地址配置在插件中心的地址里即可。
遠程監控cpu使用情況
點采樣器欄:
點擊cpu,觀察到cpu使用狀況,點擊snapshot,采取結果,可以選擇查看方法、類或包的cpu使用情況,使用工具可以查找想要查看的方法、類或包:
GC監控
選擇要監控的pid,查看GC情況
如果Old區滿了,每次回收都很少或者回收不了,說明GC有問題。
遠程監控內存泄露、解決內存溢出問題
1)內存泄露、溢出的異同
同:都會導致應用程序運行出現問題,性能下降或掛起。
異:
?內存泄露是導致內存溢出的原因之一;內存泄露積累起來將導致內存溢出。
?內存泄露可以通過完善代碼來避免;內存溢出可以通過調整配置來減少發生頻率,但無法徹底避免。
2)監測內存泄漏
?內存泄漏是指程序中間動態分配了內存,但在程序結束時沒有釋放這部分內存,從而造成那部分內存不可用的情況,重啟計算機可以解決,但也有可能再次發生內存泄露,內存泄露和硬件沒有關系,它是由軟件設計缺陷引起的。 ?
?內存泄漏可以分為4類:
a.?常發性內存泄漏。發生內存泄漏的代碼會被多次執行到,每次被執行的時候都會導致一塊內存泄漏。
b.偶發性內存泄漏。發生內存泄漏的代碼只有在某些特定環境或操作過程下才會發生。常發性和偶發性是相對的。對于特定的環境,偶發性的也許就變成了常發性的。所以測試環境和測試方法對檢測內存泄漏至關重要。
c.一次性內存泄漏。發生內存泄漏的代碼只會被執行一次,或者由于算法上的缺陷,導致總會有一塊僅且一塊內存發生泄漏。比如,在類的構造函數中分配內存,在析構函數中卻沒有釋放該內存,所以內存泄漏只會發生一次。
d.隱式內存泄漏。程序在運行過程中不停的分配內存,但是直到結束的時候才釋放內存。嚴格的說這里并沒有發生內存泄漏,因為最終程序釋放了所有申請的內存。但是對于一個服務器程序,需要運行幾天,幾周甚至幾個月,不及時釋放內存也可能導致最終耗盡系統的所有內存。所以,我們稱這類內存泄漏為隱式內存泄漏。
3)Heap dump?分析
每隔一段時間給所檢測的java應用做一次heap dump:
(或者在響應應用pid上鼠標右鍵heap dump)彈出以下提示框:
在應用服務器將此文件下載到jvisual vm所在的機器上,file--load打開此文件,如下面三圖所示:
對比上面三個截圖,發現似乎有個東西在急速飆升,仔細一看是這個對象:org.eclipse.swt.graphics.Image 在第一章圖中這個還沒排的上,第二次dump已經上升到5181個,第三次就是7845個了。漲速相當快,而且和任務管理器里面看到的GDI數量增漲一致,就是它了。
問題到這兒就比較清楚了,回到代碼里面仔細一看可以發現,是某個地方反復的用圖片來創建Image對象導致的,改掉以后搞定問題。
到這里其實我想說的是,Java使用起來其實要比C++更容易導致內存泄漏。對于C++來說,每一個申請的對象都必須明確釋放,任何沒有釋放的對象都會導致memleak,這是不可饒恕的,而且這類問題已經有很多工具和方法來解決。但是到了Java里面情況就不同了,對于Java程序員來說對象都是不需要也無法主動銷毀的,所以一般的思路是:隨用隨new,用完即丟。很多對象具體的生命周期可能連寫代碼的人自己也不清楚,或者不需要清楚,只知道某個時刻垃圾收集器會去做的,不用管。但很可能某個對象在"用完即丟"的時候在另一個不容易發現的地方被保存了一個引用,那么這個對象就永遠不會被回收。更加糟糕的是整個程序從設計之初就沒有考慮過對象回收的問題,對于C++程序員來說memleak必然是一個設計錯誤,但是對Java程序員來說這只是一個疏忽,而且似乎沒有什么好的辦法來避免。今天看到的這個問題是因為GDI泄漏會造成嚴重后果才被重視,但如果僅僅是造成內存泄漏,那這個程序可能得連續跑上個十天半個月才會發現問題。最后就是,對于c++,錯誤的代碼在測試階段就可以快速的偵測出哪怕一個byte的memleak并加以改正,但是對于java程序,理論上沒有哪個工具能夠知道是不是有泄漏,因為除了作者自己以外沒有人能夠知道一個被引用的對象是不是應該被銷毀,只有通過大量的,長期的壓力測試才能發現問題,這是很危險的一件事情。
4)解決內存溢出問題
1、java.lang.OutOfMemoryError: PermGen space
JVM管理兩種類型的內存,堆和非堆。堆是在JVM啟動時創建;非堆是留給JVM自己用的,用來存放類的信息的。它和堆不同,運行期內GC不會釋放空間。如果web app用了大量的第三方jar或者應用有太多的class文件而恰好MaxPermSize設置較小,超出了也會導致這塊內存的占用過多造成溢出,或者tomcat熱部署時侯不會清理前面加載的環境,只會將context更改為新部署的,非堆存的內容就會越來越多。
PermGen space的全稱是Permanent Generation space,是指內存的永久保存區域,這塊內存主要是被JVM存放Class和Meta信息的,Class在被Loader時就會被放到PermGen space中,它和存放類實例(Instance)的Heap區域不同,GC(Garbage Collection)不會在主程序運行期對PermGen space進行清理,所以如果你的應用中有很CLASS的話,就很可能出現PermGen space錯誤,這種錯誤常見在web服務器對JSP進行pre compile的時候。如果你的WEB APP下都用了大量的第三方jar, 其大小超過了jvm默認的大小(4M)那么就會產生此錯誤信息了。
如上圖所示,PermGen在程序運行一段時間后超出了我們指定的128MB,通過Classes視圖看到,Java在運行的同時加載了大量的類到內存中。PermGen會存儲Jar或者Class的描述信息;所以在class大量增加的同時PermGen超出了我們指定的范圍。為了讓應用穩定,我們需要探尋新的PermGen范圍。檢測時段時候后(如下圖)發現PermGen在145MB左右穩定,那么我們就得到了穩定的新參數;這樣PermGen內存溢出的問題得到解決。
2、java.lang.OutOfMemoryError: Java heap space
第一種情況是個補充,主要存在問題就是出現在這個情況中。其默認空間(即-Xms)是物理內存的1/64,最大空間(-Xmx)是物理內存的1/4。如果內存剩余不到40%,JVM就會增大堆到Xmx設置的值,內存剩余超過70%,JVM就會減小堆到Xms設置的值。所以服務器的Xmx和Xms設置一般應該設置相同避免每次GC后都要調整虛擬機堆的大小。假設物理內存無限大,那么JVM內存的最大值跟操作系統有關,一般32位機是1.5g到3g之間,而64位的就不會有限制了。
注意:如果Xms超過了Xmx值,或者堆最大值和非堆最大值的總和超過了物理內存或者操作系統的最大限制都會引起服務器啟動不起來。
?
垃圾回收GC的角色,JVM調用GC的頻度還是很高的,主要兩種情況下進行垃圾回收:
一個是當應用程序線程空閑;另一個是java內存堆不足時,會不斷調用GC,若連續回收都解決不了內存堆不足的問題時,就會報out of memory錯誤。因為這個異常根據系統運行環境決定,所以無法預期它何時出現。
根據GC的機制,程序的運行會引起系統運行環境的變化,增加GC的觸發機會。
為了避免這些問題,程序的設計和編寫就應避免垃圾對象的內存占用和GC的開銷。顯示調用System.GC()只能建議JVM需要在內存中對垃圾對象進行回收,但不是必須馬上回收。一個是并不能解決內存資源耗空的局面,另外也會增加GC的消耗。
2.7.如何避免內存泄漏、溢出
1)盡早釋放無用對象的引用。
好的辦法是使用臨時變量的時候,讓引用變量在退出活動域后自動設置為null,暗示垃圾收集器來收集該對象,防止發生內存泄露。
2) 程序進行字符串處理時,盡量避免使用String,而應使用StringBuffer。
因為每一個String對象都會獨立占用內存一塊區域,如:
1.String str = "aaa"; ? ?
2.String str2 = "bbb"; ? ?
3.String str3 = str + str2; ? ?
4.// 假如執行此次之后str , str2再不被調用,那么它們就會在內存中等待GC回收; ? ?
5.// 假如程序中存在過多的類似情況就會出現內存錯誤; ?
3) 盡量少用靜態變量。
因為靜態變量是全局的,GC不會回收。
4) 避免集中創建對象尤其是大對象,如果可以的話盡量使用流操作。
JVM會突然需要大量內存,這時會觸發GC優化系統內存環境; 一個案例如下:
1.// 使用jspsmartUpload作文件上傳,運行過程中經常出現java.outofMemoryError的錯誤, ? ?
2.// 檢查之后發現問題:組件里的代碼 ? ?
3.m_totalBytes = m_request.getContentLength(); ? ?
4.m_binArray = new byte[m_totalBytes]; ? ?
5.// totalBytes這個變量得到的數極大,導致該數組分配了很多內存空間,而且該數組不能及時釋放。 ? ?
6.// 解決辦法只能換一種更合適的辦法,至少是不會引發outofMemoryError的方式解決。 ? ?
7.// 參考:http://bbs.xml.org.cn/blog/more.asp?name=hongrui&id=3747 ?
6) 不要在經常調用的方法中創建對象,尤其是忌諱在循環中創建對象。
可以適當的使用hashtable,vector 創建一組對象容器,然后從容器中去取那些對象,而不用每次new之后又丟棄。
7) 優化配置。
a.設置-Xms、-Xmx相等;
b.設置NewSize、MaxNewSize相等;
c.設置Heap size, PermGen space:
?
?
概述
開發大型 Java 應用程序的過程中難免遇到內存泄露、性能瓶頸等問題,比如文件、網絡、數據庫的連接未釋放,未優化的算法等。隨著應用程序的持續運行,可能會造成整個系統運行效率下降,嚴重的則會造成系統崩潰。為了找出程序中隱藏的這些問題,在項目開發后期往往會使用性能分析工具來對應用程序的性能進行分析和優化。
VisualVM 是一款免費的性能分析工具。它通過 jvmstat、JMX、SA(Serviceability Agent)以及 Attach API 等多種方式從程序運行時獲得實時數據,從而進行動態的性能分析。同時,它能自動選擇更快更輕量級的技術盡量減少性能分析對應用程序造成的影響,提高性能分析的精度。
本文將對 VisualVM 的主要功能逐一介紹并探討如何利用獲得的數據進行性能分析及調優。
背景知識
性能分析的主要方式
- 監視:監視是一種用來查看應用程序運行時行為的一般方法。通常會有多個視圖(View)分別實時地顯示 CPU 使用情況、內存使用情況、線程狀態以及其他一些有用的信息,以便用戶能很快地發現問題的關鍵所在。
- 轉儲:性能分析工具從內存中獲得當前狀態數據并存儲到文件用于靜態的性能分析。Java 程序是通過在啟動 Java 程序時添加適當的條件參數來觸發轉儲操作的。它包括以下三種:
- 系統轉儲:JVM 生成的本地系統的轉儲,又稱作核心轉儲。一般的,系統轉儲數據量大,需要平臺相關的工具去分析,如 Windows 上的 windbg 和 Linux 上的 gdb。
- Java 轉儲:JVM 內部生成的格式化后的數據,包括線程信息,類的加載信息以及堆的統計數據。通常也用于檢測死鎖。
- 堆轉儲:JVM 將所有對象的堆內容存儲到文件。
- 快照:應用程序啟動后,性能分析工具開始收集各種運行時數據,其中一些數據直接顯示在監視視圖中,而另外大部分數據被保存在內部,直到用戶要求獲取快照,基于這些保存的數據的統計信息才被顯示出來。快照包含了應用程序在一段時間內的執行信息,通常有 CPU 快照和內存快照兩種類型。
- CPU 快照:主要包含了應用程序中函數的調用關系及運行時間,這些信息通常可以在 CPU 快照視圖中進行查看。
- 內存快照:主要包含了內存的分配和使用情況、載入的所有類、存在的對象信息及對象間的引用關系等。這些信息通常可以在內存快照視圖中進行查看。
- 性能分析:性能分析是通過收集程序運行時的執行數據來幫助開發人員定位程序需要被優化的部分,從而提高程序的運行速度或是內存使用效率,主要有以下三個方面:
- CPU 性能分析:CPU 性能分析的主要目的是統計函數的調用情況及執行時間,或者更簡單的情況就是統計應用程序的 CPU 使用情況。通常有 CPU 監視和 CPU 快照兩種方式來顯示 CPU 性能分析結果。
- 內存性能分析:內存性能分析的主要目的是通過統計內存使用情況檢測可能存在的內存泄露問題及確定優化內存使用的方向。通常有內存監視和內存快照兩種方式來顯示內存性能分析結果。
- 線程性能分析:線程性能分析主要用于在多線程應用程序中確定內存的問題所在。一般包括線程的狀態變化情況,死鎖情況和某個線程在線程生命期內狀態的分布情況等
VisualVM 安裝
VisualVM 是一個性能分析工具,自從 JDK 6 Update 7 以后已經作為 Oracle JDK 的一部分,位于 JDK 根目錄的 bin 文件夾下。VisualVM 自身要在 JDK6 以上的版本上運行,但是它能夠監控 JDK1.4 以上版本的應用程序。下面主要介紹如何安裝 VisualVM 以及各種 VisualVM 上的插件。
安裝 VisualVM
VisualVM 項目的官方網站目前提供英文版本和多語言支持版本下載。多語言版本主要支持英語、日語以及中文三種語言。如果下載安裝多語言版本的 VisualVM,安裝程序會依據操作系統的當前語言環境去安裝相應 VisualVM 的語言版本。最新 VisualVM 版本主要支持的操作系統包括:Microsoft Windows (7, Vista, XP, Server)、Linux、Sun Solaris、Mac OS X、HP-UX 11i。本文以 Microsoft Windows XP 為安裝環境并支持中文。
- 從?VisualVM?項目的官方網站上下載 VisualVM 安裝程序。
- 將 VisualVM 安裝程序解壓縮到本地系統。
- 導航至 VisualVM 安裝目錄的 bin 目錄,然后啟動 jvisualvm.exe。
安裝 VisualVM 上的插件
VisualVM?插件中心提供很多插件以供安裝向 VisualVM 添加功能。可以通過 VisualVM 應用程序安裝,或者從?VisualVM?插件中心手動下載插件,然后離線安裝。另外,用戶還可以通過下載插件分發文件 (.nbm 文件 ) 安裝第三方插件為 VisualVM 添加功能。
從 VisualVM 插件中心安裝插件安裝步驟 :
- 從主菜單中選擇"工具">"插件"。
- 在"可用插件"標簽中,選中該插件的"安裝"復選框。單擊"安裝"。
- 逐步完成插件安裝程序。
圖 1. VisualVM 插件管理器
根據 .nbm 文件安裝第三方插件安裝步驟 :
- 從主菜單中選擇"工具">"插件"。
- 在"已下載"標簽中,點擊"添加插件"按鈕,選擇已下載的插件分發文件 (.nbm) 并打開。
- 選中打開的插件分發文件,并單擊"安裝"按鈕,逐步完成插件安裝程序。
圖 2. 通過 .nbm 文件安裝 VisualVM 插件
功能介紹
下面我們將介紹性能分析的幾種常見方式以及如何使用 VisualVM 性能分析工具進行分析。
內存分析
VisualVM 通過檢測 JVM 中加載的類和對象信息等幫助我們分析內存使用情況,我們可以通過 VisualVM 的監視標簽和 Profiler 標簽對應用程序進行內存分析。
在監視標簽內,我們可以看到實時的應用程序內存堆以及永久保留區域的使用情況。
圖 3. 內存堆使用情況
圖 4. 永久保留區域使用情況
此外,我們也可以通過 Applications 窗口右擊應用程序節點來啟用"在出現 OOME 時生成堆 Dump"功能,當應用程序出現 OutOfMemory 例外時,VisualVM 將自動生成一個堆轉儲。
圖 5. 開啟"在出現 OOME 時生成堆"功能
在 Profiler 標簽,點擊"內存"按鈕將啟動一個內存分析會話,等 VisualVM 收集和統計完相關性能數據信息,將會顯示在性能分析結果。通過內存性能分析結果,我們可以查看哪些對象占用了較多的內存,存活的時間比較長等,以便做進一步的優化。
此外,我們可以通過性能分析結果下方的類名過濾器對分析結果進行過濾。
圖 6. 內存分析結果
CPU 分析
VisualVM 能夠監控應用程序在一段時間的 CPU 的使用情況,顯示 CPU 的使用率、方法的執行效率和頻率等相關數據幫助我們發現應用程序的性能瓶頸。我們可以通過 VisualVM 的監視標簽和 Profiler 標簽對應用程序進行 CPU 性能分析。
在監視標簽內,我們可以查看 CPU 的使用率以及垃圾回收活動對性能的影響。過高的 CPU 使用率可能是由于我們的項目中存在低效的代碼,可以通過 Profiler 標簽的 CPU 性能分析功能進行詳細的分析。如果垃圾回收活動過于頻繁,占用了較高的 CPU 資源,可能是由內存不足或者是新生代和舊生代分配不合理導致的等。
圖 7. CPU 使用情況
在 Profiler 標簽,點擊"CPU"按鈕啟動一個 CPU 性能分析會話 ,VisualVM 會檢測應用程序所有的被調用的方法。當進入一個方法時,線程會發出一個"method entry"的事件,當退出方法時同樣會發出一個"method exit"的事件,這些事件都包含了時間戳。然后 VisualVM 會把每個被調用方法的總的執行時間和調用的次數按照運行時長展示出來。
此外,我們也可以通過性能分析結果下方的方法名過濾器對分析結果進行過濾。
圖 8. CPU 性能分析結果
線程分析
Java 語言能夠很好的實現多線程應用程序。當我們對一個多線程應用程序進行調試或者開發后期做性能調優的時候,往往需要了解當前程序中所有線程的運行狀態,是否有死鎖、熱鎖等情況的發生,從而分析系統可能存在的問題。
在 VisualVM 的監視標簽內,我們可以查看當前應用程序中所有活動線程和守護線程的數量等實時信息。
圖 9. 活躍線程情況
VisualVM 的線程標簽提供了三種視圖,默認會以時間線的方式展現。另外兩種視圖分別是表視圖和詳細信息視圖。
時間線視圖上方的工具欄提供了縮小,放大和自適應三個按鈕,以及一個下拉框,我們可以選擇將所有線程、活動線程或者完成的線程顯示在視圖中。
圖 10. 線程時間線視圖
圖 11. 線程表視圖
我們在詳細信息視圖中不但可以查看所有線程、活動線程和結束的線程的詳細數據,而且也可以查看某個線程的詳細情況。
圖 12. 線程詳細視圖
快照功能
我們可以使用 VisualVM 的快照功能生成任意個性能分析快照并保存到本地來輔助我們進行性能分析。快照為捕獲應用程序性能分析數據提供了一個很便捷的方式因為快照一旦生成可以在任何時候離線打開和查看,也可以相互傳閱。
VisualVM 提供了兩種類型的快照:
- Profiler 快照:當有一個性能分析會話(內存或者 CPU)正在進行時,我們可以通過性能分析結果工具欄的"快照"按鈕生成 Profiler 快照捕獲當時的性能分析數據。
圖 13. Profiler 快照
- 應用程序快照:我們可以右鍵點擊左側 Applications 窗口中應用程序節點,選擇"應用程序快照"為生成一個應用程序快照。應用程序快照會收集某一時刻的堆轉儲,線程轉儲和 Profiler 快照,同時也會捕獲 JVM 的一些基本信息。
圖 14. 應用程序快照
轉儲功能
線程轉儲的生成與分析
VisualVM 能夠對正在運行的本地應用程序生成線程轉儲,把活動線程的堆棧蹤跡打印出來,幫助我們有效了解線程運行的情況,診斷死鎖、應用程序癱瘓等問題。
圖 15. 線程標簽及線程轉儲功能
當 VisualVM 統計完應用程序內線程的相關數據,會把這些信息顯示新的線程轉儲標簽。
圖 16. 線程轉儲結果
堆轉儲的生成與分析
VisualVM 能夠生成堆轉儲,統計某一特定時刻 JVM 中的對象信息,幫助我們分析對象的引用關系、是否有內存泄漏情況的發生等。
圖 17. 監視標簽及堆轉儲功能
當 VisualVM 統計完堆內對象數據后,會把堆轉儲信息顯示在新的堆轉儲標簽內,我們可以看到摘要、類、實例數等信息以及通過 OQL 控制臺執行查詢語句功能。
堆轉儲的摘要包括轉儲的文件大小、路徑等基本信息,運行的系統環境信息,也可以顯示所有的線程信息。
圖 18. 堆轉儲的摘要視圖
從類視圖可以獲得各個類的實例數和占用堆大小數,分析出內存空間的使用情況,找出內存的瓶頸,避免內存的過度使用。
圖 19. 堆轉儲的類視圖
通過實例數視圖可以獲得每個實例內部各成員變量的值以及該實例被引用的位置。首先需要在類視圖選擇需要查看實例的類。
圖 20. 選擇查詢實例數的類
圖 21. 實例數視圖
此外,還能對兩個堆轉儲文件進行比較。通過比較我們能夠分析出兩個時間點哪些對象被大量創建或銷毀。
圖 22. 堆轉儲的比較
圖 23. 堆轉儲的比較結果
線程轉儲和堆轉儲均可以另存成文件,以便進行離線分析。
圖 24. 轉儲文件的導出
?
?
https://www.ibm.com/developerworks/cn/java/j-5things7.html
https://www.ibm.com/developerworks/cn/java/j-5things8.html
https://www.ibm.com/developerworks/cn/java/j-lo-jvm-perf/
轉載于:https://www.cnblogs.com/xiaolang8762400/p/7087282.html
總結
以上是生活随笔為你收集整理的深入理解JAVA虚拟机 虚拟机性能监控和故障处理工具的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 兼容ie8 rgba()用法
- 下一篇: laravel中token的使用方式