如何在.NET未处于垃圾回收(GC)过程中捕获.NET进程的进程内存转储

6

当我们捕获并分析转储文件(例如在WinDbg中),常常会出现警告,因为进程在收集转储文件时可能处于GC过程中,导致数据可能不准确或命令不可用。

进行内存分析时,我们通常这样做是因为进程的内存和内存压力很高,这会促使.NET经常进行GC。

如何避免在GC期间捕获转储?是否有一种方法可以知道何时可以安全地捕获转储文件?


2
您可能想使用 PerfView,它是专为解决这个问题而设计的。帮助 | 用户指南中有一个名为“GC堆收集:冻结还是不冻结?”的部分,讨论了这个问题。下载链接为:http://www.microsoft.com/en-us/download/details.aspx?id=28567。 - Marc Sherman
如果您需要实现/测试我的答案,请给我留言。 - Markus Safar
@Mark:在你的应用程序中,是否有任何后台进程?我的意思是,如果用户没有使用它,它是否仍然可以在幕后处理一些东西? - CharithJ
@Mark:也许我们可以使用ProcDump命令并加上-pl开关。 - Thomas Weller
@Thomas 我已经用ProcDump测试了你的方法,对我很有效。我也更新了答案,希望有所帮助... - Markus Safar
1个回答

7
我虽然不是这个领域的专家,但我注意到你可以使用.NET运行时性能计数器来监视一些有趣的事情——其中之一是垃圾回收器在上次收集期间分配的字节数。在.NET Framework性能计数器中对每秒分配的字节数的描述如下:

显示在垃圾回收堆上每秒分配的字节数。该计数器只在每次垃圾回收后更新,而不是在每次分配时更新。该计数器不是随时间变化的平均值;它显示了在最后两个样本中观察到的值之间的差异,除以样本间隔的持续时间。

根据我的测试,如果将性能监视器的更新间隔设置为1秒,并仔细观察每秒分配的字节数指示器,在收集完成后似乎会显示0的值。因此,我认为您可以从这个值中推断出是否正在进行收集。
我通过在VS 2015中构建一个小应用程序来检查它,该应用程序具有显示垃圾回收是否正在进行的功能。如果是这种情况,指示器的值将不同于0。
更新(感谢Thomas)
可以使用ProcDump监视性能计数器,并以自动化方式创建转储文件。
正确的做法是:procdump ProcessName -s 1 -ma -pl "\.NET CLR Memory(ProcessName)\Allocated Bytes/second" 1000,如果该值低于一千,则会触发转储。
因此,如果该值为零,则只有在没有垃圾回收时才有效。
如果您不是在英文版操作系统上运行,则必须找出性能计数器的正确语言特定名称(可以通过查看上面提供的MSDN链接并在那里切换到不同的语言来完成)。例如,德语名称将是"\.NET CLR-Speicher(ProcessName)\Zugeordnete Bytes/Sek."

谢谢您的答复。您能否让答案更具实践性一些呢?这是不是意味着我们可以使用 ProcDump-pl 开关?如果是,哪一个开关呢?您能提供示例代码来证明这个理论吗? - Thomas Weller
@Thomas 谢谢您的赏金,;-)。 - Markus Safar
1
不用谢。我很感激你跟进并积极地处理了它。 - Thomas Weller

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