茫茫網海中的冷日
         
茫茫網海中的冷日
發生過的事,不可能遺忘,只是想不起來而已!
 恭喜您是本站第 1708092 位訪客!  登入  | 註冊
主選單

Google 自訂搜尋

Goole 廣告

隨機相片
IMG_00041.jpg

授權條款

使用者登入
使用者名稱:

密碼:


忘了密碼?

現在就註冊!

爪哇咖啡屋 : [轉貼]使用 jvisualvm 監控 Java 程序

發表者 討論內容
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[轉貼]使用 jvisualvm 監控 Java 程序

使用jvisualvm監控Java程序(本地和遠程)

0 起因

不感興趣的可以直接從 1 本地Java程序監控 開始看

0.1 發現問題

使用 top命令查看Java程序使用的內存,大於設置的最大的使用內存。( top界面查看的是 RES字段的值,設置Java程序運行最大堆內存方式是 -Xmx方法)

這是我top的結果,大概是650MB。

top查看進程運行狀態

這是我執行Java程序的腳本,可以看到-Xmx500m,已經指定了500MB的最大使用堆內存。

運行Java程序的運行腳本

0.2 問題解決

  1. 查詢 top命令結果中 RES字段的具體含義是進程使用的內存,未被換出的也算。
  2. 查詢 -Xmx的含義,就是Java程序使用的最大堆內存。
  3. 通過以上可以說明,這兩個含義並不對應。Java中除了堆內存,還有棧內存。所以比我們設置的500MB多也正常。

由此考慮,如何才能監控Java程序使用內存狀況呢?經過一番查找知道了Java自帶的jvisualvm,但是找到的教程,按照操作又踩了很多坑。這裡自己總結一下完整過程。

1 本地Java程序監控

1.1 本地啟動jvisualvm

在 JDK根目錄的 bin文件夾下可以找到 jvisualvm,直接在終端敲命令 jvisualvm
就可以運行,然後可以看到運行界面。

jVisualVM界面

然後我隨便運行一個不會馬上關閉的Java程序,例如:


public class Main {
public static void main(String[] args) throws InterruptedException {
for (int i = 10000; i > 0; i--) {
System.out.println();
Thread.sleep(1000);
}
}
}
複製代碼

然後,我們看 jvisualvm界面,在右側可以看到我們運行的程序,雙擊就可以在右側看到我們的程序:

Main程序在VisualVM中的展示

具體監控的內容暫時不做介紹,我們繼續講啟動方式。

1.2 IntelliJ IDEA的VusalVM

我使用的是 IntelliJ Idea進行後台開發的。在 IntelliJ Idea中有一個插件 VusualVM Luncher

安裝完成之後重啟IDEA,然後在以前運行的地方可以看到:

如果你之前實驗的jvisualvm窗口還開著,那你可以先把它關閉。然後使用 Run With VisualVM運行程序,第一次會出現配置界面:

選擇JDK根目錄下, bin文件夾下的 jvisualvm就可以了,完成配置,運行程序就可以看到啟動了 VisualVM,在Windows下可以直接打開運行的應用,但在Mac上不行,要自己雙擊才行。

2 遠程Java程序監控

服務器開發有很多,打的包也不同。我們是直接打成Jar包,然後使用jar命令直接運行jar包。本文只提供jar包方式運行的方法。其他的例如war,使用Tomcat啊什麼的可以根據自己開發的具體環境,去網上查找。但是注意 2.3步提到的,我在這一步踩了很久的坑。

2.1 遠程服務器配置JXM

在遠程服務器上的JDK根目錄下的 /jre/lib/management
文件夾下,將 jmxremote.password.template文件複製一份 jmxremote.password,然後打開 jmxremote.password文件。

將裡面的這兩行註釋去掉, monitorRole和 controlRole就是用戶名, QED和 R&D分別是密碼,最後更改了密碼,當然和可以使用同樣的格式自己添加用戶,對於用戶的權限是在 jmxremote.access文件中配置的,這兩個角色的權限默認已經配置了,如果自己添加的用戶,你需要自己在這個文件中添加相應的配置,我們暫時就使用 controlRole這個角色,因為他的權限比較多:


#monitorRole QED
#controlRole R&D
複製代碼

2.2 修改啟動jar的參數

在運行jar的時候添加如下的參數,沒有換行:


true
複製代碼

hostname就是主機的地址, port就是端口號,請確認這個端口號不要被佔用。 ssl就是要不要加密,我這裡鏈接的開發環境就不加密了, authenticate就是要不要用戶認證,賬號密碼就是 上一步 中配置的。

然後重新運行程序。

2.3 設置防火牆

敲黑板,注意這裡

運行完程序之後關閉服務器的防火牆,有很多教程都是讓把上一步中設置的端口號打開,但是其實,JXM還需要監聽兩個隨機的接口。要不直接關了防火牆,要不就把使用到的端口都打開。

2.4 配置jvisualvm

在左側 遠程右擊 添加遠程主機:

填寫信息之後,可以看到左側 遠程下多了一個遠程主機,然後右擊,選擇 添加JXM鏈接:

然後鏈接OK。

3 VisualVM的使用方法

然後我通過VisualVM監控遠程那個程序,看到堆內存只用了300多MB。

VisualVM的使用方法在網上有相當多的文章,這裡推薦一篇我覺得還不錯的,我就不再寫了:

使用 VisualVM 進行性能分析及調優


原文出處:使用jvisualvm监控Java程序(本地和远程) - 掘金
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[轉貼]使用 VisualVM 進行性能分析及調優

使用 VisualVM 進行性能分析及調優

虞 立軍, 王 建光, 和 倪 力
2013 年 2 月 18 日發佈

概述

開發大型 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 插件管理器

點擊查看大圖

圖 1. VisualVM 插件管理器

根據 .nbm 文件安裝第三方插件安裝步驟 :

  • 從主菜單中選擇「工具」>「插件」。
  • 在「已下載」標籤中,點擊"添加插件"按鈕,選擇已下載的插件分發文件 (.nbm) 並打開。
  • 選中打開的插件分發文件,並單擊"安裝"按鈕,逐步完成插件安裝程序。
圖 2. 通過 .nbm 文件安裝 VisualVM 插件

點擊查看大圖

圖 2. 通過 .nbm 文件安裝 VisualVM 插件

功能介紹

下面我們將介紹性能分析的幾種常見方式以及如何使用 VisualVM 性能分析工具進行分析。

內存分析

VisualVM 通過檢測 JVM 中加載的類和對像信息等幫助我們分析內存使用情況,我們可以通過 VisualVM 的監視標籤和 Profiler 標籤對應用程序進行內存分析。

在監視標籤內,我們可以看到實時的應用程序內存堆以及永久保留區域的使用情況。

圖 3. 內存堆使用情況

點擊查看大圖

圖 3. 內存堆使用情況
圖 4. 永久保留區域使用情況

點擊查看大圖

圖 4. 永久保留區域使用情況

此外,我們也可以通過 Applications 窗口右擊應用程序節點來啟用「在出現 OOME 時生成堆 Dump」功能,當應用程序出現 OutOfMemory 例外時,VisualVM 將自動生成一個堆轉儲。

圖 5. 開啟「在出現 OOME 時生成堆」功能

點擊查看大圖

圖 5. 開啟「在出現 OOME 時生成堆」功能

在 Profiler 標籤,點擊「內存」按鈕將啟動一個內存分析會話,等 VisualVM 收集和統計完相關性能數據信息,將會顯示在性能分析結果。通過內存性能分析結果,我們可以查看哪些對像佔用了較多的內存,存活的時間比較長等,以便做進一步的優化。

此外,我們可以通過性能分析結果下方的類名過濾器對分析結果進行過濾。

圖 6. 內存分析結果

點擊查看大圖


圖 6. 內存分析結果

CPU 分析

VisualVM 能夠監控應用程序在一段時間的 CPU 的使用情況,顯示 CPU 的使用率、方法的執行效率和頻率等相關數據幫助我們發現應用程序的性能瓶頸。我們可以通過 VisualVM 的監視標籤和 Profiler 標籤對應用程序進行 CPU 性能分析。

在監視標籤內,我們可以查看 CPU 的使用率以及垃圾回收活動對性能的影響。過高的 CPU 使用率可能是由於我們的項目中存在低效的代碼,可以通過 Profiler 標籤的 CPU 性能分析功能進行詳細的分析。如果垃圾回收活動過於頻繁,佔用了較高的 CPU 資源,可能是由內存不足或者是新生代和舊生代分配不合理導致的等。

圖 7. CPU 使用情況

點擊查看大圖

圖 7. CPU 使用情況

在 Profiler 標籤,點擊「CPU」按鈕啟動一個 CPU 性能分析會話 ,VisualVM 會檢測應用程序所有的被調用的方法。當進入一個方法時,線程會發出一個「method entry」的事件,當退出方法時同樣會發出一個「method exit」的事件,這些事件都包含了時間戳。然後 VisualVM 會把每個被調用方法的總的執行時間和調用的次數按照運行時長展示出來。

此外,我們也可以通過性能分析結果下方的方法名過濾器對分析結果進行過濾。

圖 8. CPU 性能分析結果

點擊查看大圖


圖 8. CPU 性能分析結果

線程分析

Java 語言能夠很好的實現多線程應用程序。當我們對一個多線程應用程序進行調試或者開發後期做性能調優的時候,往往需要瞭解當前程序中所有線程的運行狀態,是否有死鎖、熱鎖等情況的發生,從而分析系統可能存在的問題。

在 VisualVM 的監視標籤內,我們可以查看當前應用程序中所有活動線程和守護線程的數量等實時信息。

圖 9. 活躍線程情況

點擊查看大圖

圖 9. 活躍線程情況

VisualVM 的線程標籤提供了三種視圖,默認會以時間線的方式展現。另外兩種視圖分別是表視圖和詳細信息視圖。

時間線視圖上方的工具欄提供了縮小,放大和自適應三個按鈕,以及一個下拉框,我們可以選擇將所有線程、活動線程或者完成的線程顯示在視圖中。

圖 10. 線程時間線視圖

點擊查看大圖

圖 10. 線程時間線視圖
圖 11. 線程表視圖

點擊查看大圖


圖 11. 線程表視圖

我們在詳細信息視圖中不但可以查看所有線程、活動線程和結束的線程的詳細數據,而且也可以查看某個線程的詳細情況。

圖 12. 線程詳細視圖

點擊查看大圖

圖 12. 線程詳細視圖

快照功能

我們可以使用 VisualVM 的快照功能生成任意個性能分析快照並保存到本地來輔助我們進行性能分析。快照為捕獲應用程序性能分析數據提供了一個很便捷的方式因為快照一旦生成可以在任何時候離線打開和查看,也可以相互傳閱。

VisualVM 提供了兩種類型的快照:

  • Profiler 快照:當有一個性能分析會話(內存或者 CPU)正在進行時,我們可以通過性能分析結果工具欄的「快照」按鈕生成 Profiler 快照捕獲當時的性能分析數據。
圖 13. Profiler 快照

點擊查看大圖

圖 13. Profiler 快照
  • 應用程序快照:我們可以右鍵點擊左側 Applications 窗口中應用程序節點,選擇「應用程序快照」為生成一個應用程序快照。應用程序快照會收集某一時刻的堆轉儲,線程轉儲和 Profiler 快照,同時也會捕獲 JVM 的一些基本信息。
圖 14. 應用程序快照

點擊查看大圖

圖 14. 應用程序快照

轉儲功能

線程轉儲的生成與分析

VisualVM 能夠對正在運行的本地應用程序生成線程轉儲,把活動線程的堆棧蹤跡打印出來,幫助我們有效瞭解線程運行的情況,診斷死鎖、應用程序癱瘓等問題。

圖 15. 線程標籤及線程轉儲功能

點擊查看大圖

圖 15. 線程標籤及線程轉儲功能

當 VisualVM 統計完應用程序內線程的相關數據,會把這些信息顯示新的線程轉儲標籤。

圖 16. 線程轉儲結果

點擊查看大圖

圖 16. 線程轉儲結果

堆轉儲的生成與分析

VisualVM 能夠生成堆轉儲,統計某一特定時刻 JVM 中的對象信息,幫助我們分析對象的引用關係、是否有內存洩漏情況的發生等。

圖 17. 監視標籤及堆轉儲功能

點擊查看大圖


圖 17. 監視標籤及堆轉儲功能

當 VisualVM 統計完堆內對像數據後,會把堆轉儲信息顯示在新的堆轉儲標籤內,我們可以看到摘要、類、實例數等信息以及通過 OQL 控制台執行查詢語句功能。

堆轉儲的摘要包括轉儲的文件大小、路徑等基本信息,運行的系統環境信息,也可以顯示所有的線程信息。

圖 18. 堆轉儲的摘要視圖

點擊查看大圖

圖 18. 堆轉儲的摘要視圖

從類視圖可以獲得各個類的實例數和佔用堆大小數,分析出內存空間的使用情況,找出內存的瓶頸,避免內存的過度使用。

圖 19. 堆轉儲的類視圖

點擊查看大圖

圖 19. 堆轉儲的類視圖

通過實例數視圖可以獲得每個實例內部各成員變量的值以及該實例被引用的位置。首先需要在類視圖選擇需要查看實例的類。

圖 20. 選擇查詢實例數的類

點擊查看大圖

圖 20. 選擇查詢實例數的類
圖 21. 實例數視圖

點擊查看大圖

圖 21. 實例數視圖

此外,還能對兩個堆轉儲文件進行比較。通過比較我們能夠分析出兩個時間點哪些對像被大量創建或銷毀。

圖 22. 堆轉儲的比較

點擊查看大圖

圖 22. 堆轉儲的比較
圖 23. 堆轉儲的比較結果

點擊查看大圖

圖 23. 堆轉儲的比較結果

線程轉儲和堆轉儲均可以另存成文件,以便進行離線分析。

圖 24. 轉儲文件的導出

總結

本文首先簡要列舉了一些性能分析相關的背景知識。然後介紹了 VisualVM 的下載和安裝。最後從內存性能、CPU 性能、快照功能以及轉儲功能四個方面展開,進一步說明了如何使用 VisualVM 進行性能分析。通過本文的介紹,相信讀者對性能分析會有一定的瞭解,並可以利用 VisualVM 進行性能分析。


原文出處:使用 VisualVM 进行性能分析及调优
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[轉貼]Jvisualvm -- JAVA 性能分析工具

Jvisualvm--JAVA性能分析工具

JDK 自帶的 JAVA 性能分析工具 。 它已經在你的 JDK bin 目錄裡了,只要你使用的是 JDK1.6 Update7 之後的版本。點擊一下 jvisualvm.exe 圖標它就可以運行了。

這裡是 VisualVM 的官方網站: https://visualvm.dev.java.net ,資料很全,同時提供 VisualVM 最近版本下載。

1. 安裝

只要安裝 JDK 即可,運行 jvisualvm.exe ,選擇【工具】——【插件】——【可用插件】


wKiom1MZqv6gTLYOAAHQALi3EVQ254.jpg·

2 使用

2.1.
遠程機器設置

要從遠程應用程序中檢索數據,需要在遠程 JVM 上運行 jstatd 實用程序。 即要進行以下操作:

1) 在 jdk 安裝目錄的 bin 目錄下新建文件 jstatd.all.policy ,文件內容為:  


permission java.security.AllPermission;


};


2) 再新建文件 jstatd. sh ,文件內容為:

./jstatd -J-Djava.security.policy=jstatd.all.policy


3) 啟動 jstat : nohup jstatd.sh & ( 默認啟動端口為 1099)

4) 配置 resin.conf ,把以下註釋打開:

   <!-- no use args


     <jvm-arg>-Xdebug</jvm-arg>

     <jvm-arg>-Dcom.sun.management.jmxremote</jvm-arg>

2.2. 添加遠程監控機器

wKioL1MZs6mSYFZyAAEP56Xo1Tw306.jpg

2.3. 配置 Jconsole

1) 在應用的 resin 配置文件中加配置:

<jvm-arg>-Dcom.sun.management.jmxremote</jvm-arg>

<jvm-arg>-Dcom.sun.management.jmxremote.port=9009</jvm-arg>

<jvm-arg>-Dcom.sun.management.jmxremote.ssl=false</jvm-arg>


<jvm-arg>-Dcom.sun.management.jmxremote.authenticate=false</jvm-arg>

2) 選擇 Tools 菜單裡的 Plugins 菜單,點擊 'VisualVM-JConsole' 然後點擊 'Install' 按鈕

3) 安裝完畢後重新啟動 VisualVm

4) 配置 JConsole 頁簽,點擊 'JConsole Plugins' 按鈕

5) 點擊 'Add JAR/Folder' 按鈕,

6) 添加 JDK_HOME/demo/management/JTop/JTop.jar

7) 重新打開監控頁面,可以看到 JConsole 正常工作


wKiom1MZs_mgO1XbAAJmd4w8Pqc594.jpg

2.4. 遠程監控 cpu 使用情況

點採樣器欄:

wKioL1MZs_HzhnGDAAGh15q1Mts787.jpg

點擊 cpu ,觀察到 cpu 使用狀況,點擊 snapshot ,採取結果,可以選擇查看方法、類或包的 cpu 使用情況,使用 工具可以查找想要查看的方法、類或包:


wKioL1MZtBzBJoWQAAF75iFVDSA718.jpg

2.5. GC 監控

1) 選擇要監控的 pid ,查看 GC 情況

wKioL1MZtFPBa-3qAAH24ueOTx8191.jpg

如果 Old 區滿了,每次回收都很少或者回收不了,說明 GC 有問題 。

2.6. 遠程監控內存洩露、解決內存溢出問題

1) 內存洩露、溢出的異同

同:都會導致應用程序運行出現問題,性能下降或掛起。

異:

v 內存洩露是導致內存溢出的原因之一;內存洩露積累起來將導致內存溢出。


v 內存洩露可以通過完善代碼來避免;內存溢出可以通過調整配置來減少發生頻率,但 無法徹底避免。

2) 監測內存洩漏

· 內存 洩漏 是指程序中間動態分配了內存,但在程序結束時沒有釋放這部分內存,從而造成那部分內存不可用的情況,重啟計算機可以解決,但也有可能再次發生內存洩露,內存洩露和硬件沒有關係,它是由軟件設計缺陷引起的。  

· 內存洩漏可以分為4類:

a. 常發性內存洩漏 。發生內存洩漏的代碼會被多次執行到,每次被執行的時候都會導致一塊內存洩漏。

b. 偶發性內存洩漏 。發生內存洩漏的代碼只有在某些特定環境或操作過程下才會發生。常發性和偶發性是相對的。對於特定的環境,偶發性的也許就變成了常發性的。所以測試環境和測試方法對檢測內存洩漏至關重要。

c. 一次性內存洩漏 。發生內存洩漏的代碼只會被執行一次,或者由於算法上的缺陷,導致總會有一塊僅且一塊內存發生洩漏。比如,在類的構造函數中分配內存,在析構函數中卻沒有釋放該內存,所以內存洩漏只會發生一次。

d. 隱式內存洩漏 。程序在運行過程中不停的分配內存,但是直到結束的時候才釋放內存。嚴格的說這裡並沒有發生內存洩漏,因為最終程序釋放了所有申請的內存。但是對於一個服務器程序,需要運行幾天,幾周甚至幾個月,不及時釋放內存也可能導致最終耗盡系統的所有內存。所以,我們稱這類內存洩漏為隱式內存洩漏。

3) Heap dump 分析

每隔一段時間給所檢測的 java 應用做一次 heap dump :

wKiom1MZtKTTJ5K3AABJbkv4_d4875.jpg

(或者在響應應用 pid 上鼠標右鍵 heap dump )彈出以下提示框:

wKioL1MZtKaiSdicAAB6rwX6AqE541.jpg

在應用服務器將此文件下載到 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)那麼就會產生此錯誤信息了。

wKioL1MZtlHREhrhAAMFKXoTEMw761.jpg

如上圖所示, PermGen 在程序運行一段時間後超出了我們指定的 128MB ,通過 Classes 視圖看到, Java 在運行的同時加載了大量的類到內存中。 PermGen 會存儲 Jar 或者
Class 的描述信息;所以在 class 大量增加的同時 PermGen 超出了我們指定的範圍。為了讓應用穩定,我們需要探尋新的 PermGen 範圍。檢測時段時候後(如下圖)發現 PermGen 在 145MB 左右穩定,那麼我們就得到了穩定的新參數;這樣 PermGen 內存溢出的問題得到解決。

wKiom1MZtrWRVGIQAAMV1WiIwr0717.jpg

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的消耗。

wKiom1MZuOfBZE4hAAJS5vcnocE082.jpg


2.7. 如何避免內存洩漏、溢出

1) 盡早釋放無用對象的引用。

好的辦法是使用臨時變量的時候,讓引用變量在退出活動域後自動設置為null,暗示垃圾收集器來收集該對象,防止發生內存洩露。

2) 程序進行字符串處理時,盡量避免使用String,而應使用StringBuffer。

因為每一個String對象都會獨立佔用內存一塊區域,如:

1.

2.

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  

5) 盡量運用對像池技術以提高系統性能。

生命週期長的對象擁有生命週期短的對象時容易引發內存洩漏,例如大集合對像擁有大數據量的業務對象的時候,可以考慮分塊進行處理,然後解決一塊釋放一塊的策略。

6) 不要在經常調用的方法中創建對象,尤其是忌諱在循環中創建對象。


可以適當的使用hashtable,vector 創建一組對像容器,然後從容器中去取那些對象,而不用每次new之後又丟棄。

7) 優化配置。

a. 設置-Xms、-Xmx相等;

b. 設置NewSize、MaxNewSize相等;

c. 設置Heap size, PermGen space:


c著作權歸作者所有:來自51CTO博客作者zhouanyafu的原創作品,如需轉載,請註明出處,否則將追究法律責任

原文出處: Jvisualvm--JAVA性能分析工具-安雅个人技术博客-51CTO博客
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[轉貼]基於 JVisualVM 的可視化監控

基於JVisualVM的可視化監控

其他 · 發表

目錄 能夠 線上 tex moni 方便 man 系統屬性 ans

監控本地的java進程

本小節我們介紹一下如何使用JDK自帶的jvisualvm工具來監控本地的Java進程,該工具是一個圖形化的監控工具。

jvisualvm官方文檔地址如下:

https://visualvm.github.io/documentation.html

一、介紹

VisualVM,能夠監控線程,內存情況,查看方法的CPU時間和內存中的對 象,已被GC的對象,反向查看分配的堆棧(如100個String對象分別由哪幾個對象分配出來的).

從界面上看還是比較簡潔的,左邊是樹形結構,自動顯示當前本機所運行的Java程序,還可以添加遠程的Java VM,其中括號裏面的PID指的是進程ID。OverView界面顯示VM啟動參數以及該VM對應的一些屬性。Monitor界面則是監控Java堆大小,Permgen大小,Classes和線程數量。jdk不同版本中界面會不太一致,如有的含cpu監控,有的則不含(jdk1.6.0_10未包含)。

二、JVisualVM能做什麽

VisualVM 是Netbeans的profile子項目,已在JDK6.0 update 7 中自帶,能夠監控線程,內存情況,查看方法的CPU時間和內存中的對 象,已被GC的對象,反向查看分配的堆棧(如100個String對象分別由哪幾個對象分配出來的)。

三、jvisualvm在哪

jvisualvm位於JAVA_HOME/bin目錄下,如下圖:

基於JVisualVM的可視化監控

直接雙擊就可以打開該程序,打開後界面如下:
基於JVisualVM的可視化監控

如果只是監控本地的java進程,是不需要配置參數的,直接打開就能夠進行監控。首先我們需要在本地打開一個Java程序,例如我打開IDEA,這時在jvisualvm界面就可以看到與IDEA相關的Java進程了:
基於JVisualVM的可視化監控

點擊一個進程,就可以看到該進程的概述信息,該進程的JVM參數以及系統屬性等信息都能夠查看到:

基於JVisualVM的可視化監控

點擊 “監視” 就能夠看到CPU、內存、類以及線程的活動狀況,點擊右上角的 “堆Dump” 就能夠導出內存映像文件:
基於JVisualVM的可視化監控

除了導出,也還可以導入內存映像文件,只不過分析功能上沒有MAT強大:
基於JVisualVM的可視化監控

點擊 “線程” 就能夠看到該進程內部的所有線程,以及線程的運行狀況等信息。如果點擊右上角的 “線程Dump” 就會導出一個內容與jstack打印內容一致的文件:

基於JVisualVM的可視化監控

點擊 “抽樣器” 界面中的 “CPU ” 就可以動態的看到每個方法的執行時間,當我們的代碼執行的比較慢了,就可以通過抽樣器來查看是哪一個方法執行的比較慢:
基於JVisualVM的可視化監控

而點擊 “內存” 的話,就可以實時的、動態的查看到每個類實例對象的數量以及這些實例所占用的內存大小:
基於JVisualVM的可視化監控

在Profiler界面上,可以對CPU、內存進行性能分析,分析後會給出分析結果:

基於JVisualVM的可視化監控

接下來我們下載兩個比較實用的插件,首先到VisualVM插件中心,地址如下:

https://visualvm.github.io/pluginscenters.html

因為有時候自帶的插件地址可能無法使用,所以我們需要自行配置可用的地址:
基於JVisualVM的可視化監控

回到jvisualvm中,點擊菜單欄中的 “工具“ 選項,再點擊子菜單的 ”插件“ 選項:
基於JVisualVM的可視化監控


然後按照下圖配置插件地址:
基於JVisualVM的可視化監控

配置好插件地址後,按照下圖勾選以下兩個插件:
基於JVisualVM的可視化監控

按照提示一步步的進行安裝:
基於JVisualVM的可視化監控

基於JVisualVM的可視化監控

安裝完成:
基於JVisualVM的可視化監控

插件安裝完成後需要重啟jvisualvm才會生效,這時會看到選項卡中多了一個 “Visual GC” 選項,點擊該選項後,可以動態的查看到JVM內存結構各個區域的運行狀況,極大方便我們進行各個區內存的監控及調優:
基於JVisualVM的可視化監控

另一個插件的作用就是可以讓我們針對某個進程編寫BTrace腳本,右鍵點擊一個進程,在彈出來的菜單中,選擇“Trace application...”,就可以編寫BTrace腳本了:

基於JVisualVM的可視化監控


監控遠程的java進程

在上一小節中,我們簡單介紹了如何使用JDK自帶的jvisualvm工具來監控本地的Java進程。而本小節我們將介紹一下如何使用jvisualvm來監控遠程的java進程,我們這裏以線上服務器的Tomcat為例。

打開jvisualvm,雙擊 “遠程” 選項,添加一個遠程主機,即遠程的服務器:
基於JVisualVM的可視化監控

然後編輯Tomcat的catalina.sh文件,在該文件中加入如下配置內容:


[email protected] ~]# vim /home/tomcat/apache-tomcat-8.5.8/bin/catalina.sh
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9004 -Dcom.su
n.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false
-Djava.net.preferIPv4Stack=true -Djava.rmi.server.hostname=119.23.250.83"

配置簡單說明:

  • -Dcom.sun.management.jmxremote添加一個jmx遠程連接屬性
  • -Dcom.sun.management.jmxremote.port=9004 指定連接的端口號
  • -Dcom.sun.management.jmxremote.authenticate=false 是否啟用驗證
  • -Dcom.sun.management.jmxremote.ssl=false 是否啟用ssl
  • Djava.net.preferIPv4Stack=true 是否優先使用ipv4
  • -Djava.rmi.server.hostname=119.23.250.83 指定遠程主機的ip地址

如下圖:
基於JVisualVM的可視化監控

增加完配置後,重啟Tomcat,查看是否有9004端口,有的話就代表配置成功了,如下:


[email protected] ~]# netstat -lntp |grep java
tcp 0 0 0.0.0.0:9004 0.0.0.0:* LISTEN 13399/java
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 13399/java
tcp 0 0 0.0.0.0:46199 0.0.0.0:* LISTEN 13399/java
tcp 0 0 0.0.0.0:32859 0.0.0.0:* LISTEN 13399/java
tcp 0 0 127.0.0.1:8005 0.0.0.0:* LISTEN 13399/java
tcp 0 0 0.0.0.0:8009 0.0.0.0:* LISTEN 13399/java
[[email protected] ~]#

回到jvisualvm中,添加JMX連接,配置連接地址和端口,如下:
基於JVisualVM的可視化監控
基於JVisualVM的可視化監控

註意,如果你使用的是阿裏雲等雲服務器的話,不僅需要配置防火墻規則來開放端口,還需要到雲服務器的安全組規則中,增加相應的端口規則,如下:
基於JVisualVM的可視化監控

連接成功後,如下:

基於JVisualVM的可視化監控

同樣的,可以像監控本地進程一樣,監控遠程的進程,在界面的操作上是一模一樣的。唯一不同的也就是需要添加一個遠程主機,然後到遠程的Java進程上配置一些jmx參數而已:
基於JVisualVM的可視化監控

以上我們是以Tomcat這種服務型的進程作為一個示例,只需要去配置Tomcat的腳本文件就可以了。那麽如果我們需要監控的是自己線上跑的一個Java進程需要怎麽進行配置呢?其實也是一樣的,同樣的是使用這些參數,只不過是作為啟動參數而已,在啟動項目的時候加上即可,如下:


[email protected] ~]# nohup java -Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9005 -Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false -Djava.net.preferIPv4Stack=true -Djava.rmi.server.hostname=119.23.250.83
-jar monitor_tuning-0.0.1-SNAPSHOT.jar &

成功啟動後,也是使用同樣的方式進行連接,註意端口不要弄錯了:
基於JVisualVM的可視化監控

連接成功後也是一樣的:
基於JVisualVM的可視化監控

然後我們就可以愉快的在本地監控遠程的Java進程了,而且還是圖形化的,免去了敲命令的煩惱。

我們來做一個堆內存溢出的實驗,看看jvisualvm能否監控到內存的變化,在瀏覽器上訪問我們之前在基於JDK命令行工具的監控一文中所編寫的/head接口。訪問後如下,可以看到堆內存的變化很激烈,利用jvisualvm工具進行監控,就很明顯的就能夠觀察到該進程的異常:

基於JVisualVM的可視化監控

所以線上監控不能少,是我們必須要掌握的一種技能。監控相當於我們的眼睛,如果沒有監控工具,那我們就相當於瞎子一樣兩眼一抹黑。無法看到內存、線程的使用情況,當出現異常的時候,也難以定位問題發生的原因。

基於JVisualVM的可視化監控


原文出處: 基於JVisualVM的可視化監控 - IT閱讀
前一個主題 | 下一個主題 | 頁首 | | |



| Powered by XOOPS 2.0 © 2001-2008 The XOOPS Project|