Dot-Net

如何探索 .NET 應用程序中的託管堆以辨識可能的記憶體優化?

  • November 16, 2021

我們有一個 .NET 應用程序,我們的客戶認為它對於大規模部署來說太大了,我們想了解是什麼導致了我們的記憶體佔用,以及在不完全放棄 .NET 和 wpf 的情況下是否可以做得更好。

我們有興趣改進 Total Size 和 Private Working Set (pws)。在這個問題中,我只想看看 pws。VMMap 通常報告 105 mb 的 pws。其中 11mb 是鏡像,31mb 是堆,52mb 是託管堆,7mb 是私有數據,其餘的是堆棧、頁表等。

這裡最大的獎勵是託管堆。我們可以直接在我們自己的程式碼(即我們創建和管理的對象和視窗)中計算大約 8mb 的託管堆。其餘部分是由我們使用的框架元素創建的假定 .NET 對象。

我們想要做的是確定框架的哪些元素解釋了這種使用的哪一部分,並可能重新建構我們的系統,以盡可能避免使用它們。誰能建議如何進行這項調查?

進一步澄清:

到目前為止,我已經使用了許多工具,包括出色的 ANTS 分析器和帶有 SOS 的 WinDbg,它們確實允許我查看託管堆中的對象,但這裡真正感興趣的不是“什麼?”,而是“為什麼? ’ 理想情況下,我想說,“嗯,這裡創建了 10mb 的對象,因為我們使用 WCF。如果我們編寫自己的本地傳輸,我們可以節省 8mb 的質量風險和開發工作量。”

不可能對超過 300,000 個對象執行 gcroot。

WinDbg可能對您來說是一個有用的工具。它帶有適用於 Windows 的調試工具

應用程序執行後,您可以附加 WinDbg 並探索託管堆。(或者您可以進行記憶體轉儲並離線探索)。它將能夠非常快速地告訴您消耗最大記憶體量的對像類型。

首先,您需要載入啟用託管應用程序調試的SOS擴展:

.loadby sos mscorwks

然後您可以使用!dumpheap獲取堆資訊,該-stat開關提供有關分配哪些類型的整體堆資訊:

!dumpheap -stat

-type參數提供有關指定類型的已分配實例的特定資訊:

!dumpheap -type System.String

還有許多其他命令可能對您有所幫助,例如:

  • !gcroot - 跟踪分配的對象備份它的根以查找它為什麼在記憶體中。
  • !dumpobj- 轉儲一個特定的對象,這樣你就可以看到它的內容。
  • !EEHeap- 給出一些一般的堆統計資訊。

MSDN 有SOS 命令及其開關的完整列表。

WinDbg 是一個相當複雜的工具,但是如果您搜尋幫助您入門,線上上有很多教程和指南。或者,我可以推薦 John Robbins 所著的Debugging Microsoft .NET 2.0 Applications一書,其中詳細介紹了 WinDbg 和 SOS 的 .net 調試功能。

您可以將 SOS 擴展載入到 Visual Studio 中,而不是將其輸入到即時視窗中,然後您應該能夠直接在 VS 即時視窗中使用 SOS 命令:

.load SOS.dll

您還可能會發現CLR Profiler和本使用指南很有幫助。

引用自:https://stackoverflow.com/questions/2957105