在.NET中确定对象图的内存使用情况

3
出于好奇和需要找到代码中的一些潜在问题,我喜欢在Web应用程序运行时跟踪一些常规值,特别是某些对象图的分配内存。我们的应用程序将一些数据永久保存在内存中以保证其可靠性。这可能会累积到几GB的内存,而其他几乎相同的应用程序只分配了一两个GB的内存。 由于需要高性能,我们无法在运行时附加内存分析器。因此,分析对象图以打印出在某些情况下哪些数据部分很大,哪些不太大,会很有帮助,这将有助于更好地理解数据的变化,并潜在地优化应用程序的行为。
对象图意味着从一个确定的对象开始,测量其在内存中的大小,递归地遍历所有引用的对象,包括所有属性、字段、列表及其所有元素等,然后添加它们的相应大小,直到我们获得有关该对象和所有相关对象使用的内存量的信息。
实际上,我想要的答案是:当我释放对这个锚定对象的最后一个引用时,GC能够在下一次清理该对象图时释放多少内存?
2个回答

3
如果您不使用分析工具,那么您将面临很大的困难。
关于测量对象图大小的问题已经在 SO 上被提出多次,例如: 如何确定 .NET 中复杂对象的大小? 如何获取内存中的对象大小? 每个问题都收到了一堆答案(请随意阅读它们),但老实说它们都或多或少地很糟糕。您必须承认,没有可靠的方法来获取这些信息,因为它是一个实现细节。
但是让我们假设您实际需要的不是准确的测量,而是一些大概的数字,以知道“Big Boy Objects”在哪里。
- 序列化您的对象图
我可以想到的一个简单方法是使用二进制格式将您的对象序列化到内存流中,并检查其大小。
- 使用转储文件
另一种方法可能是创建应用程序的转储文件,并使用它们来分析内存。Visual Studio 2013具有新的内存分析器,可以帮助您从在生产机器上收集的.dmp文件中了解应用程序的.NET内存使用情况。它还显示所有对象的大小:

enter image description here

这是一个两部分的介绍:

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

第二部分: 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上的文档有一个关于非线性堆行走器的示例,用于计算对象的大小。它与SOS中的!objsize相同,因此该命令接受一个对象作为参数,并计算它保持活动状态的对象数,并报告给定对象保持活动状态的所有对象的总大小。

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


3
这让我感到困惑:内存分析工具如何获取这些信息?从同一个进程中甚至更容易获得。 - Sebastian P.R. Gingter

3
不确定这是否符合您的要求,但Windbg的SOS扩展提供了!objsize命令,可以递归地确定对象的大小,包括所有引用的对象。您可以将其附加到运行中的进程上,或者获取内存转储(例如使用procdump),然后附加到转储文件以进行离线分析。但是,!objdump的输出仅在子对象仅从您的初始对象可达时才是对您最终问题的答案(当然,任何其他引用都会防止子对象树被收集,即使您的初始对象变得不可达)。
其中一个原因是在进程内部进行此操作如此困难,在一定程度上是由于运行时必然隐藏了关于内存表示方面的许多细节。通过使用不安全代码可以克服其中一些问题,但这仍然是非常复杂的。因此,使用类似Windbg中的SOS这样“知道”CLR内部情况的工具可以使该过程变得更加容易,明显的限制是它必须从“外部”而不是从内部进行操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接