PerfView 概述:
PerfView是一個可以幫助你分析CPU和記憶體問題的工具軟體。它非常輕量級也不會入侵診斷的程式,在診斷過程中對診斷的程式影響甚微。
Visual Studio自帶的效能分析功能在CPU佔用、時間消耗、記憶體分配等方面的診斷效果還算不錯,但PerfView可以提供更加豐富的診斷分析資訊。
在這篇文章中,我將使用PerfView給你展現如下功能:
- GC回收發生的頻率以及回收所消耗的時間;
- 獲取導致Large object分配的原因;
- 記憶體被誰佔用了;
- 對比哪個託管物件增大的最快。
測試程式
現在我們準備一個將會導致記憶體洩露的程式,用來確保使用PerfView可以達到我們所期望的效果。它是一個WinForm應用程式,後臺程式碼如下:、
public partial class Form1 : Form { private List<int[]> arrays = new List<int[]>(); Random random = new Random(); public Form1() { InitializeComponent(); Thread thread = new Thread(Start); thread.IsBackground = true; thread.Start(); } private void Start(object obj) { while (true) { int[] a = new int[random.Next(90000, 100000)]; arrays.Add(a); Thread.Sleep(10); } } }
使用PerfView進行跟蹤
開啟PerfView,你將會看到如下視窗:
PerfView的使用手冊被整合在這個程式中,你可以選單欄來進行訪問。
然後點選選單“Collect-->Collect”來進行資料採集,用來分析生成診斷結果:
無需修改任何初始化配置,點選“Start Collection”按鈕,PerfView將會開始採集所有程式的事件資料。
數十秒之後,你可以點選“Stop Collection”按鈕,PerfView將會停止採集並生成診斷檔案“PerfViewData.etl.zip”:
獲取GC Stats
雙擊“GCStats”報表,將會彈出一個視窗,視窗中顯示了每一個程式GC資訊,找到我們的測試程式。
關於測試程式我們將會得到如下彙總資訊表:
進一步往下看,還會顯示GC觸發的原因:
如上圖所示,這次GC的collection的發生是因為large object的分配。
獲取導致large object分配的原因
從PerfView的主介面,雙擊開啟“GC Heap Alloc Stacks”視窗,然後雙擊測試程式的程式,之後彈出的視窗將根據記憶體分配從大到小的次序顯示堆疊資訊:
PerfView會將所有的large object分配都歸類在LargeObject節點下面,雙擊該節點可以看到如下資訊:
備註:如果你在上圖所示的介面中看到“OTHER<<clr?>>”,可以對其滑鼠右擊,然後點選“Lookup Symbols”,來獲取CLR和Windows的功能名稱。
上圖中主要列的說明如下:
Inc%:表示該物件分配的位元組佔所有記錄分配的百分比;
Inc:該物件分配位元組的總數;
Inc Ct:該物件分配的次數。
從上圖可以看出,巨多的large object都是來自Start方法的Int32陣列,PerView精確地診斷出我們預期的效果。
誰造成了記憶體洩露
PerfView可以通過heap dump來檢視佔用記憶體的物件的路徑。
從主介面點選選單項“Memory-->Tale Heap Snapshot”,彈出視窗如下圖所示:
找到我們的測試程式並選中,然後點選“Dump GC Heap”按鈕,數秒後再點選“CLose”按鈕,最後會生成一個“.gcdump”檔案。
雙擊開啟“WindowsFormsApplication1.gcdump”視窗,顯示如下所示:
PrefView精確地診斷出,是static variables佔用了記憶體。
使用兩個Heap Dump來檢視物件所佔記憶體的變化情況
在應用程式連續執行的情況下,對其進行兩次Take Heap Sanpshot,確保兩次生成的檔名稱不一致。同時開啟這兩個.gcdump檔案的視窗,通過任一一個視窗的diff選單項功能,都能以另一個視窗的資料為基準進行對比。