1. 程式人生 > >使用JProfiler進行記憶體分析幹不好測試的程式設計師不是一個好工程師!

使用JProfiler進行記憶體分析幹不好測試的程式設計師不是一個好工程師!

在最近的工作中,通過JProfiler解決了一個記憶體洩漏的問題,現將檢測的步驟和一些分析記錄下來,已備今後遇到相似問題時可以作為參考。

 

執行環境:

Tomcat6,jdk6,JProfiler8

 

記憶體洩漏的現象:

1. 在伺服器中執行某些批量操作的時候,發現記憶體只升不降;就算gc後,記憶體也不能被完全釋放;

2. 除非重啟tomcat伺服器,記憶體永遠不會被釋放,反覆執行這些操作,會導致無可用記憶體,tomcat死掉;

 

使用JProfiler檢查記憶體洩漏的步驟:

1. 初始化檢驗環境:

切換到“Live Memory-->All Objects”標籤,可以看到當前tomcat中的物件情況,注意jprofiler其他版本可能位置不一樣.

在執行操作前,需要先F4,執行“Run GC”,使jvm進行記憶體回收清理無效的物件.為了便於比較記憶體的增長情況,可以點選右鍵--->"Mark Current",

來將當前記憶體使用情況作為參照;點選後會顯示“Difference”列,該列會列出物件數量的變化和變化比率

2.開啟記憶體記錄: 

點選“Start Recordings”按鈕,開始記錄。執行這步的主要目的是為下面“Heap Walker”設定一個監控區間;如果不記錄的話“Heap Walker”將分析jvm虛擬機器的所有記憶體,即耗時又不能準確的發現記憶體洩漏的原因。

3. 執行操作,執行gc;

 使用壓力工具訪問被測應用,執行完之後再次F4進行GC----這樣是為了消除可以回收的物件。執行記憶體回收後,仍然存在於記憶體中的物件有可能是洩漏的物件。如下圖instance count中紅色的部門為不能回收的物件,difference列列出了增加的物件數量和增。以String為例,在該操作中增加了31751個物件增幅達到了14%,隨後會在HeapWalker中觀察這些物件,分析哪些物件是洩漏的。一般引起洩漏的物件包括:String、char[]、HashMap、Concurrenthashmap等,這類物件需要重點關注下;

4. 關閉記憶體記錄:

點選“Stop Recordings”關閉記憶體記錄,告訴jProfiler把這段記錄作為分析物件;

5. 找到增加迅速的物件型別,開啟HeapWalker:

在檢視中找到增長快速的物件型別,本例Concurrenthashmap的增長速度很快。在memory檢視中找到Concurrenthashmap---點右鍵----選擇“Show Selectiion In Heap Walker”,切換到HeapWarker 檢視;切換前會彈出選項頁面,注意一定要選擇“Select recorded  objects”,這樣Heap Walker會在剛剛的那段記錄中進行分析;否則,會分析tomcat的所有記憶體物件,這樣既耗時又不準確;

6. 在HeapWalker中,找到洩漏的物件;

HeapWarker 會分析記憶體中的所有物件,包括物件的引用、建立、大小和數量;

 

HeapWarker檢視下方可以進行頁面切換:

通過切換到References頁籤,可以看到這個類的具體物件例項。

 為了在這些記憶體物件中,找到洩漏的物件(應該被回收),可以在該物件上點選右鍵,選擇“Use Selected Instances”縮小物件範圍;

單擊OK按鈕

7. 通過引用分析該物件:

在References引用頁籤中,可以看到該物件的的引用關係,可以切換incoming/outcoming,顯示引用的型別:

incoming  表示顯示這個物件被誰引用;

outcoming 表示顯示這個物件引用的其他物件;

 

選擇“Show In Graph”將引用關係使用圖形方式展現;

選中該物件,點選“Show Paths To GC Root”,會找到引用的根節點;

在上圖中,我們可以發現,這個HashMap Segment物件最終的引用是在ConcurrentHashMap和ReentranLock物件中;

8. 通過建立分析該物件:

如果第7步還不能定位記憶體洩露的地方,我們可以嘗試使用Allocations頁籤,該頁籤顯示物件是如何創建出來的;

我們可以從建立方法開始檢查,檢查所有用到該物件的地方,直到找到洩漏位置;

 

 

 

 

持續學習、持續收穫才能帶來持續的滿足和快樂!