当.NET不在垃圾收集(GC)中时,如何捕获.NET进程的进程内存转储

当捕获转储文件并对其进行分析时(例如在WinDbg中),我经常会收到警告:数据可能不准确,或者命令可能无法访问,因为当收集转储文件时,进程位于GC的中间。

在进行内存分析时,我们经常这样做,因为进程中的内存很高而内存压力很高,我猜这会强制.NET到GC。

如何在GC期间避免转储? 有没有办法知道何时可以安全地捕获转储文件?

我不是这个领域的专家,但我注意到你可以使用.NET运行时的性能计数器来监控一些有趣的事情 – 其中一个是垃圾收集器在上一次收集期间分配的字节数。 .NET Framework中性能计数器中的已Allocated Bytes/second说明:

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

根据我的测试,如果您将性能监视器的更新间隔设置为1秒并仔细查看Allocated Bytes/second的指示器,则在收集完成后似乎显示值为0 。 所以我认为,你可以从这个值中得出集合是否正在进行中。

我通过在VS 2015中构建一个小应用程序来检查它,该应用程序能够显示是否正在进行垃圾收集。 如果是这样的话,指标的值不同于0。

更新 (谢谢托马斯)

可以使用ProcDump监视性能计数器并以自动方式创建转储。 这样做的正确方法是: procdump ProcessName -s 1 -ma -pl "\.NET CLR Memory(ProcessName)\Allocated Bytes/second" 1000 ,如果值低于procdump ProcessName -s 1 -ma -pl "\.NET CLR Memory(ProcessName)\Allocated Bytes/second" 1000 ,将触发转储。

如果没有垃圾收集,则该值应该仅为零。

如果您不使用英文版操作系统,则必须找到性能计数器的正确语言特定名称(可以通过查看上面提供的MSDN链接并切换到其他语言来完成)。 例如,德语名称为"\.NET CLR-Speicher(ProcessName)\Zugeordnete Bytes/Sek."