部分出于好奇 - 我们想知道我们的应用程序中发生了什么 - 部分是因为我们需要在代码中找到一些潜在的问题,我喜欢在Web应用程序的运行时跟踪一些常规值。这尤其包括某些对象图的已分配内存。
我们的应用程序会将一些数据永久保存在内存中,以使其可靠。这可以总计几GB的内存,而其他几乎完全相同的应用程序只分配一个或两个。
由于性能要求,我们无法在运行时附加内存分析器。 因此,在运行时分析对象图以打印出在某些情况下数据的哪些部分如此之大以及哪些部分不是那么大将会很棒。这将有助于我们更好地了解数据会发生什么,并可能优化我们的应用程序的行为。
对象图表意味着,从某个对象开始,测量其在内存中的大小,递归地跟踪所有引用的对象,通过所有属性,字段,列表及其所有元素等,并添加相应的大小,直到我们知道该对象和所有相关对象使用了多少内存。
实际上,我想要回答的问题是:当我刚刚发布这个锚点对象的最后一个引用时,GC在下次运行时清理这个对象图时能够释放多少? / p>
答案 0 :(得分:3)
如果您没有使用分析器,那么您将面临艰巨的任务。
关于测量对象图大小的问题已在SO上多次提出,例如:
Ways to determine size of complex object in .NET?
How to get object size in memory?
每个问题都收到了一堆答案(随意阅读),但说实话,他们都或多或少地吮吸。您必须接受没有可靠的方法来获取此信息,因为它是一个实现细节。
但是让我们假设你真正需要的不是一个准确的测量,而是一些大概的数据来了解“大男孩物体”的位置。
我能想到的一个简单方法是使用二进制格式化程序将对象序列化为内存流并检查其大小。
另一种方法可能是创建应用程序的转储文件并使用它们来分析内存。 Visual Studio 2013有一个新的内存分析器,可以帮助您从生产机器上收集的.dmp文件中了解应用程序的.NET内存使用情况。
它还会显示所有对象的大小:
有两部分介绍:
CLR MD是一个用于构建诊断工具的C#API。它为您提供了SOS和PSSCOR调试器扩展可以在简单,快速的C#API中执行的功能和灵活性。
github上的文档有一个关于非线性堆walker的示例,用于计算对象的大小。它与SOS中的!objsize的作用相同,因此该命令将对象作为(参数并计算它保持活动的对象数以及报告(给定对象保持活动的所有对象的总大小。
答案 1 :(得分:2)
目前尚不清楚这是否符合您的要求,但Windbg的SOS扩展提供了!objsize
命令来递归地确定对象的大小,包括所有引用的对象。您可以附加到正在运行的进程,也可以进行内存转储(例如,使用procdump
),然后附加到转储文件以脱机执行分析。但是,!objdump
的输出只是最终问题的答案,如果子对象只能从初始对象到达(任何其他引用当然会阻止子对象树即使您的初始对象无法访问也不会被收集。
这个过程本身如此困难的原因部分是由于运行时必然隐藏了关于内存表示的许多细节。其中一些可以通过使用不安全的代码来克服,但它仍然是非平凡的,因此在Windbg中使用类似SOS的东西“知道”CLR的内部使得该过程更容易,具有明显的局限性它必须从过程的“外部”而不是从内部完成。