.NET Memory Profiler 使用簡介


1         簡介

.Net Memory Profiler(以下簡稱Profiler):專門針對於.NET程序,功能最全的內存分析工具,最大的特點是具有內存動態分析(Automatic Memory Analysis)功能。

2         安裝

安裝程序為SciTech.NET.Memory.Profiler.v4.0.114. 安裝+注冊機

下載地址:http://download.csdn.net/detail/wmlunge/4972685

安裝完成后直接覆蓋安裝目錄下的 memprofilerstandalone.dll 、netmemprofilerbase.dll 和 netmemprofilerconsole.exe,然后雙擊license.reg 文件即可完成注冊。

3         使用方法

Profler可以調試4種類型的.NET程序,分別為:

l  桌面應用程序

l  WPF程序

l  ASP.NET程序

l  .NET Service程序

對應選擇軟件的文件菜單如下

Profler調試共有三種方式選擇:

l  啟動跟蹤(Profiler Application)

選定對應的調試方式,如調試桌面程序,選中Profiler Application,然后選擇需要啟動的執行文件,Profiler將作為宿主程序啟動程序開始實時監控內存.

l  附加進程(Attach Process)

Profiler附加到指定的進程上,此時不能實時監控內存情況,只能夠收集內存鏡像.

l  導入內存鏡像(Import Memory Dump)

可以選擇dmp為后綴的內存鏡像文件,比如Windbg以及DebugDiag導出的鏡像文件,此時不能實時監控內存情況,只能夠收集內存鏡像且不能跟蹤非托管資源.

3.1    軟件設置

為了加快Profiler分析內存類型實例的速度,需要設置程序的符號路徑即(Symbol File Locations),進入菜單Tool->Options->Preferences->Symobl File Locations,得到彈出菜單如下圖.

選中”Retrive Debug Symbols ..”選項,該選項是為了將被調試程序需要的PDB符號文件從Http://msdl.microsoft.com/download/symbols下載下來.並選定一個目錄緩存原來下過的符號路徑,如果有其他的分目錄存放路徑,則指定”Additional Symbols file locations”選項.

:如果選擇了從微軟網站下載符號會影響調試程序的啟動時間,建議使用本地符號集緩存

3.2    操作說明

3.2.1   啟動程序

首先,選擇需要調試類型,調試ZLBH桌面程序,選擇 Profiler Application,選擇好需要啟動的程序exe文件.

如果需要設置啟動參數,則設置好命令行參數以及工作目錄.

選擇”Next”進行收集數據的一些選項設置,一般直接按”Star”按鈕開始調試程序.

3.2.2   收集數據

選擇菜單欄的收集按鈕,收集堆數據,第一個為收集全部堆上的數據,第二個為只收集第0代的數據.

3.2.3   重新啟動和停止

調試完畢后通過停止按鈕跟蹤程序,通過啟動按鈕重新啟動上一次的調試程序.

-啟動

-停止

3.2.4   查看收集數據

Profiler上有6個頁卡,分別為:

l   Type/Resource 類型/資源頁卡

l   Type/Resource Details類型/資源明細頁卡

l   Instance Details 實例明細頁卡

l   Call Stacks/Methods調用堆棧頁卡

l   Navtive Memory 本地內存頁卡

l   Real-Time-實時跟蹤頁卡

3.2.4.1  Type/Resource 類型/資源頁卡

類型/資源頁卡,可以看到當前收集的內存快照的實例數/實例字節數等信息.

通過類型/資源網格的上部可以過濾出需要的信息,共有四個地方可以過濾,從左到右分別為:

l   資源類型

托管資源 

非托管資源

l   警告類型

Profiler自動分析的內存問題警告類型

l   命名空間

類型的命名空間

l   類型名稱

按輸入過濾類型名稱

類型的過濾還可以通過,”Show type/Resource”下拉框過濾出所有的已有類型.“Show hierarcical”通過命名空間分類顯示類型和資源.

Live Instances 列顯示當前活動的實例數

Total:總共建立的實例數

New:新建的實例數

Remved:已經銷毀的實例數

Delta:New –Removed,新建和銷毀數的差值.

Comparison SnapShop:另一個用來比較的內存快照來比較兩個快照的差別

3.2.4.2  Type/Resource Details類型/資源明細頁卡

通過在Type/Resource視圖中選中某個類型則顯示類型資源的明細信息,包括該類型下所有的類型實例.

左側包括的信息包括:

l   是否新建的實例

l   實例號

l   被引用的次數

l   實例所占用的內存大小

l   實例的代信息

l   實例的子級對象所占用的內存大小

右側包含Allocation StacksShortest Root Paths,如果不是實時跟蹤,則沒有Allocation Stacks頁卡.

l   Allocation Stacks顯示的是Win32調用路徑

l   Shortest Root Paths 顯示的是從根對象到當前實例的引用路徑,查看順序從下往上,為根到實例的路徑.

 

 

3.2.4.3  Instance Details 實例明細頁卡

通過點擊Type/Resource Details類型/資源明細頁卡上的單個實例,顯示這個實例的明細信息,顯示的主要內容包括:

l   Referenced By 被引用的關系

l   References 引用的關系

l   Field Value 屬性的值

3.2.4.4  Call Stacks/Methods調用堆棧頁卡

顯示調用及方法堆棧,可以選擇只包含托管代碼和非托管代碼

顯示方法所調用的函數及被調用的函數關系,如圖:

3.2.4.5  Navtive Memory 本地內存頁卡

用於顯示進程的本地內存信息,本地內存是被操作系統管理的內存,而不是CLR管理的內存。

3.2.4.6  Real-Time-實時跟蹤頁卡

如果通過Profiler Application調試程序,則能夠顯示出Real-Time頁卡,主要內容有:

l   Graph and Statistics

通過圖形顯示實時的內存分配情況,包括:總共實例數、存貨實例數、Disposed實例數等

l   Type/Resources

實時的顯示出類型和資源信息,並顯示最后一次gc存活的實例數以及總共的實例數。

3.2.5   自動內存分析

.NET Memory Profiler分析工具能夠根據內存鏡像以及實時跟蹤進行自動內存問題分析,提供6個嚴重級別的提示,分別為嚴重警告、警告、輕度警告、間接警告、建議、提示。

其中對應的嚴重級別又會有不同的原因分類提示:

嚴重警告

Potential Memory Leak

潛在的內存泄漏

 

Disposed instance with direct EventHandler roots

實例已Disposed但有直接的EventHandler

一個Disposed的實例直接被一個EventHandler根化,這個實例只能通過代理訪問到

Disposed instance with direct delegate roots

實例已Disposed但有直接的Delegate

 

Undisposed instances (release resource, no finalizer)

沒有被Disposed的實例

一個Disposable實例被GC回收,但是因為沒有finalzier方法而沒有正確的Dispose,從未導致外部的非托管資源沒有被釋放掉

警告

Direct EventHandler roots

被一個EventHandler直接根化

一個實例直接被一個EventHandler根化,需要檢查這個實例以及這個EventHandler實例,是否實例被EventHandler把持

Disposed instance

Disposed的實例

一個實例雖然被Disposed但是還是標記為可到達(Reachable),需要進一步檢查該實例是否是活動的(alive

Undisposed instances (release resource and remove external references)

沒有被Disposed的實例

一個實例被GC回收,但是沒有dispose,Disposable類型的實例由於沒有Dispose,導致非托管資源以及外部引用不能被移除

Undisposed instances (release resource)

沒有被Disposed的實例

Undisposed instances (remove external references)

沒有被Disposed的實例

輕度警告

Direct delegate roots

直接被代理所根化

一個Disposed的實例直接被一個Delegate根化,這個實例只能通過代理訪問到

Pinned instance

被釘住的實例

釘在內存中的對象因為實例不能移動,會影響GC回收效率

間接警告

Disposed instance with indirect EventHandler roots

Disposed的對象被EventHandler間接根化

 

Indirect EventHandler roots

非直接被EventHandler所根化

 

Disposed instance with indirect delegate roots

Disposed的對象被Deletegate間接根化

 

Indirect delegate roots

非直接被代理所根化

 

建議

Undisposed instances (perform action)

沒有被Disposed的實例

實例被回收,但是沒有正確的Dispose,實例在Dispose的過程中,需要執行一些ExitClearup操作,包括:寫數據到文件、提交或回滾事務、清除緩存、刪除臨時文件等

Undisposed instances (memory/resource utilization)

實例在Dispose的過程中需要Dispose其他實例,比如:釋放COM接口、suppress finalization

提示

Large instance

大型實例對象

需要存放到大對象堆的實例

Undisposed instances (clear references)

沒有被Disposed的實例

Dispose實例需要清空其他實例的引用的操作,但是沒有執行

Undisposed instances (no action)

 

Undisposed instances (unclassified)

       

 

4         常見內存問題

4.1    使用了非托管資源的類

非托管資源的類是指本身是被CLR管理的,而且其管理的非托管資源也可以被CLR自動回收,因為CLR只能跟蹤非托管資源的生存期,但是不能主動去做GC,所以GC的時機不確定,所以在使用完后應及時釋放。

例如:調用FileStream

 FileStream file = new FileStream(@"c:\Test.txt", FileMode.Open);   

連續兩次調用程序會報“文件正在使用中”的異常,如果兩次調用中間調用強制回收,則不會報異常。

再例如:使用ODP.NETOracleCommandOracleDataReader,Close后還需要Dispose;

OracleCommand cmd = new OracleCommand();

cmd.CommandText = sbSQL.ToString();

cmd.Connection = conn;

cmd.Parameters.Add(p1);

OracleDataReader dr = cmd.ExecuteReader();

if (dr.Read())

  {

//…

dr.Close();

  }

else

  {

  }

dr.Dispose();

cmd.Dispose();

常見的使用了非托管資源的類如下:

ApplicationContext

Component

ComponentDesigner

Brush

Container

Context

Cursor

FileStream

DataSet

Font

Icon

Image

Matrix

Texture

OdbcDataReader

OleDBDataReader

Pen

Regex

Socket

StreamWriter

Timer

Transaction

DataReader

Ping

Tooltip

Bitmap

SerialPort

以上列出的類均繼承了IDisposable接口,需要在使用完后調用Dispose方法釋放或者使用Using語句塊,比如DataTableDataSetDataReaderTransactionBitMap…

4.2    Win32APICOM

指通過本地API函數與托管對象進行交互(比如:通過 P/Invoke方式調用本地DLLDLLImport聲明靜態外部函數和COM Interop)所用到的非托管資源。

例如:當通過DLL Import調用 API函數GetDC函數時忘了調用ReleaseDC去釋放設備句柄造成4個字節的內存泄漏。

再如:智能文檔中使用的Word以及導出EXCEl功能用到的OfficeCOM非托管組件,在關閉時GC不能識別COM組件而造成有時候無法對COM對象進行釋放,這時候可以通過以下兩個InteropServices函數進行釋放

l  System.Runtime.InteropServices.Marshal.ReleaseComObject(comObject);

遞減與指定的 COM 對象關聯的指定 運行時可調用包裝 (RCW) 的引用計數。

返回值為關聯的 RCW 的引用計數的新值。此值通常為零,因為無論調用包裝COM 對象的托管客戶端有多少,RCW 僅保留對該對象的一次引用。

所以通過這個方法顯式的通過CLR釋放非托管 COM 對象上的所有引用。

l  System.Runtime.InteropServices.Marshal.FinalReleaseComObject(comObject);

通過將 運行時可調用包裝 (RCW) 的引用計數設置為 0,釋放對它的所有引用。

返回值為與 comObject參數關聯的 RCW 的引用計數的新值,如果釋放成功,則為 0(零)。

4.3    事件造成的內存泄漏

l  當不需要使用事件時,應退訂事件,為了確保安全可以在Dispose方法中退訂事件.

l  當對象不再觸發事件時,應該將對象設為null來移除所有的事件訂閱者

4.4    動態添加生成控件造成內存泄漏

動態生成引用了非托管資源的控件后,注意一定要Dispose();

   例如:     

RichTextBox rtb = new RichTextBox();

frm.Controls.Add(rtb);

frm.Controls.Remove(rtb);

rtb.Dispose();

下載地址: SciTech.NET.Memory.Profiler.v4.0.114. 安裝+注冊機

安裝完成后直接覆蓋安裝目錄下的 memprofilerstandalone.dll 、netmemprofilerbase.dll 和 netmemprofilerconsole.exe,然后雙擊license.reg 文件即可完成注冊。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM