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菜單項功能,都能以另一個窗口的數據為基准進行對比。