2014-10-08 37 views
3

部分出於好奇 - 我們想知道我們的應用程序中發生了什麼 - 部分原因是我們需要在代碼中發現一些潛在的問題,我喜歡在運行時跟蹤一些常規值我們的網絡應用程序。這尤其包括某些對象圖的分配內存。確定.NET中對象圖的內存使用情況

我們的應用程序會將一些數據永久保留在內存中以使其可靠可用。這可以總結爲幾GB的內存,而做幾乎相同的東西的其他應用程序只分配一個或兩個。

由於要求的性能,我們無法在運行時連接內存分析器。 因此,在運行時分析一個對象圖很好,可以打印出哪些部分的數據在某些情況下非常大,哪些不那麼大。這將有助於我們更好地理解數據會發生什麼並可能優化應用程序的行爲。

對象圖的裝置,從一定對象開始,測量其在存儲器大小,遞歸地跟蹤通過所有屬性,字段,列表與他們的所有元素等所有引用的對象和加入它們的相應尺寸,直到我們具有信息該對象和所有相關對象使用了多少內存。

實際上,我想回答的問題是:當我剛剛釋放對此錨點對象的最後一個引用時,在下次運行時清理此對象圖時GC能夠釋放多少?

回答

3

如果您沒有使用探查器,您將面臨艱鉅的任務。

關於測量對象圖的大小的問題已經提出對SO多次,例如:

Ways to determine size of complex object in .NET?

How to get object size in memory?

每個問題已收到一堆答案(隨意通讀他們),但說實話,他們都吸或多或少。您必須接受沒有可靠的方式來獲取這些信息,因爲它是一個實現細節。

但讓我們假設你實際需要的不是一個準確的測量,而是一些球場數字來知道「大男孩物體」在哪裏。

  • 您的序列化對象圖

一個簡單的方法我能想到的是用二進制格式序列化你的對象到內存流和檢查的大小。

  • 使用轉儲文件

另一種方法可以創建應用程序的轉儲文件,並用它們來分析內存。 Visual Studio 2013有一個新的內存分析器,可幫助您從生產機器上收集的.dmp文件中瞭解.NET內存對應用程序的使用情況。

它還會顯示所有對象的大小:

enter image description here

有兩個部分介紹了這個:

1部分: http://blogs.msdn.com/b/visualstudioalm/archive/2013/06/20/using-visual-studio-2013-to-diagnose-net-memory-issues-in-production.aspx

第2部分: http://blogs.msdn.com/b/visualstudioalm/archive/2013/10/16/net-memory-analysis-enhancements-in-visual-studio-2013.aspx

  • 使用Microsoft.Diagnostics.Runtime 「CLR MD」

CLR MD是用來建立診斷工具,C#API。它爲您提供SOS和PSSCOR調試器擴展可以在簡單,快速的C#API中執行的功能和靈活性。

github上的文檔有一個關於用於計算對象大小的非線性堆棧walker的示例。它與SOS中的!objsize相同,因此該命令將一個對象作爲參數並計數它保持活動的對象的數量以及報告(給定對象保持活動狀態的所有對象的總大小)

https://github.com/Microsoft/dotnetsamples/blob/master/Microsoft.Diagnostics.Runtime/CLRMD/docs/WalkingTheHeap.md

+0

這是什麼讓我感到困惑:內存分析器如何獲取這些信息?這應該在同一過程中更有可能。 – 2014-10-08 18:41:22

1

目前尚不清楚這是否符合您的要求,但SOS擴展WinDBG的提供!objsize命令,以確定一個對象遞歸包括所有引用的對象的大小。您可以附加到正在運行的進程,或採取內存轉儲(例如,使用procdump),然後附加到轉儲文件以脫機執行分析。但!objdump的輸出只會是最終問題的答案,如果子對象只有可從初始對象到達(任何其他引用當然會阻止即使您的初始對象無法訪問也收集子對象樹)。

從流程本身來看,這很困難的原因部分是由於運行時必然會隱藏很多關於內存表示的細節。其中一些可以通過使用不安全的代碼來克服,但它仍然是非常重要的,所以在Windbg中使用類似SOS的東西可以「知道」CLR的內部結構,這使得過程變得更加容易,它必須從過程的「外部」完成,而不是從內部完成。