JvisualVM-windows 使用
一****.Java VisualVM 概述
VisualVM 是一款免費的 \ 集成了多個 JDK 命令行工具的可視化工具,它能為您提供強大的分析能力,對 Java 應用程序做性能分析和調優。這些功能包括生成和分析海量數據、跟蹤內存泄漏、監控垃圾回收器、執行內存和 CPU 分析,同時它還支持在 MBeans 上進行瀏覽和操作。
開發大型 Java 應用程序的過程中難免遇到內存泄露、性能瓶頸等問題,比如文件、網絡、數據庫的連接未釋放,未優化的算法等。隨着應用程序的持續運行,可能會造成整個系統運行效率下降,嚴重的則會造成系統崩潰。為了找出程序中隱藏的這些問題,在項目開發后期往往會使用性能分析工具來對應用程序的性能進行分析和優化。
VisualVM 是一款免費的性能分析工具。它通過 jvmstat、JMX、SA(Serviceability Agent)以及 Attach API 等多種方式從程序運行時獲得實時數據,從而進行動態的性能分析。同時,它能自動選擇更快更輕量級的技術盡量減少性能分析對應用程序造成的影響,提高性能分析的精度。
在內存分析上,Java VisualVM 的最大好處是可通過安裝 Visual GC 插件來分析 GC(Gabage Collection)趨勢、內存消耗詳細狀況。
二、背景知識
性能分析的主要方式
-
監視:監視是一種用來查看應用程序運行時行為的一般方法。通常會有多個視圖(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 上的插件。
下載地址:https://visualvm.github.io/
雙擊啟動 JVisualVM 后可以看到窗口左側 “應用程序”欄中有 “ 本地 ”、“遠程 ” 、“快照 ” 三個項目。
Java VisualVM 默認沒有安裝 Visual GC 插件,需要手動安裝,點擊菜單欄 工具 -> 插件 安裝 Visual GC
安裝完成后重啟 Java VisualVM,Visual GC 界面自動打開,即可看到 JVM 中堆內存的分代情況
要看懂上面的圖必須理解 Java 虛擬機的一些基本概念:
堆 (Heap) :JVM 管理的內存叫堆
分代:根據對象的生命周期長短,把堆分為 3 個代:Young,Old 和 Permanent,根據不同代的特點采用不同的收集算法,揚長避短也。
-
-
**Young(年輕代)
年輕代分三個區。一個 Eden 區,兩個 Survivor 區。大部分對象在 Eden 區中生成。當 Eden 區滿時,還存活的對象將被復制到 Survivor 區(兩個中的一個),當這個 Survivor 區滿時,此區的存活對象將被復制到另外一個 Survivor 區,當這個 Survivor 區也滿了的時候,從第一個 Survivor 區復制過來的並且此時還存活的對象,將被復制 “年老區 (Tenured)”。需要注意,Survivor 的兩個區是對稱的,沒先后關系,所以同一個區中可能同時存在從 Eden 復制過來對象,和從前一個 Survivor 復制過來的對象,而復制到年老區的只有從第一個 Survivor 復制過來的對象。而且,Survivor 區總有一個是空的。參考文章:http://www.iteye.com/topic/894148**
-
**Tenured(年老代)
**年老代存放從年輕代存活的對象。一般來說年老代存放的都是生命期較長的對象。
-
**Perm(持久代)
**用於存放靜態文件,如今 Java 類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應用可能動態生成或者調用一些 class,例如 hibernate 等,在這種時候需要設置一個比較大的持久代空間來存放這些運行過程中新增的類。持久代大小通過 - XX:MaxPermSize = 進行設置。
-
GC 的基本概念
gc 分為 full gc 跟 minor gc(Young GC 也就是 Minor GC),當每一塊區滿的時候都會引發 gc。
- Scavenge GC
一般情況下,當新對象生成,並且在 Eden 申請空間失敗時,就觸發了 Scavenge GC,堆 Eden 區域進行 GC,清除非存活對象,並且把尚且存活的對象移動到 Survivor 區。然后整理 Survivor 的兩個區。 - Full GC
對整個堆進行整理,包括 Young、Tenured 和 Perm。Full GC 比 Scavenge GC 要慢,因此應該盡可能減少 Full GC。有如下原因可能導致 Full GC:
-
上一次 GC 之后 Heap 的各域分配策略動態變化
-
System.gc() 被顯示調用
-
Perm 域被寫滿
-
Tenured 被寫滿
內存溢出 out of memory,是指程序在申請內存時,沒有足夠的內存空間供其使用,出現 out of memory;比如申請了一個 integer, 但給它存了 long 才能存下的數,那就是內存溢出。
內存泄露 memory leak,是指程序在申請內存后,無法釋放已申請的內存空間,一次內存泄露危害可以忽略,但內存泄露堆積后果很嚴重,無論多少內存, 遲早會被占光。其實說白了就是該內存空間使用完畢之后未回收。
“本地” 下顯示的是在 localhost 運行的 Java 程序的資源占用情況,如果本地有 Java 程序在運行的話啟動 Java VisualVM 即可看到相應的程序名,點擊程序名打開相應的資源監控菜單,以圖形的形式列出程序所占用的 CPU 、 Heap 、 PermGen 、類、線程的 統計信息。雙擊 Local 下的任一節點,看到右邊的變化 ,你可以監控 CPU ,內存,類,線程等運行狀況,實時監控服務器性能。
右鍵 VisualVM 我們可以看到 Thread Dump, Heap Dump
做 Thread Dump 很快,馬上就可以看到結果
Heap Dump 要稍花費一些時間(可以看到當前 heap 里對象的數量及占用的比例,做 OOM 很好用)
四、功能介紹
下面我們將介紹性能分析的幾種常見方式以及如何使用 VisualVM 性能分析工具進行分析。
1)內存分析
VisualVM 通過檢測 JVM 中加載的類和對象信息等幫助我們分析內存使用情況,我們可以通過 VisualVM 的監視標簽和 Profiler 標簽對應用程序進行內存分析。
在監視標簽內,我們可以看到實時的應用程序內存堆以及永久保留區域的使用情況。
圖 3. 內存堆使用情況
圖 4. 永久保留區域使用情況
此外,我們也可以通過 Applications 窗口右擊應用程序節點來啟用 “在出現 OOME 時生成堆 Dump” 功能,當應用程序出現 OutOfMemory 例外時,VisualVM 將自動生成一個堆轉儲。
圖 5. 開啟 “在出現 OOME 時生成堆” 功能
在 Profiler 標簽,點擊 “內存” 按鈕將啟動一個內存分析會話,等 VisualVM 收集和統計完相關性能數據信息,將會顯示在性能分析結果。通過內存性能分析結果,我們可以查看哪些對象占用了較多的內存,存活的時間比較長等,以便做進一步的優化。
此外,我們可以通過性能分析結果下方的類名過濾器對分析結果進行過濾。
圖 6. 內存分析結果
2)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 的線程標簽提供了三種視圖,默認會以時間線的方式展現。另外兩種視圖分別是表視圖和詳細信息視圖。(本次使用的 jdk1.7 只有一個時間線視圖)
時間線視圖上方的工具欄提供了縮小,放大和自適應三個按鈕,以及一個下拉框,我們可以選擇將所有線程、活動線程或者完成的線程顯示在視圖中。
圖 10. 線程時間線視圖
快照功能
我們可以使用 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. 堆轉儲的比較結果
線程轉儲和堆轉儲均可以另存成文件,以便進行離線分析。