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

How to capture a process memory dump of a .NET process when .NET is not in the middle of a garbage collection (GC)

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

我们在做内存分析的时候,经常是因为进程上的内存比较大,内存压力大,估计逼迫.NET频繁GC。

如何避免在 GC 期间进行转储?有没有办法知道什么时候捕获转储文件是安全的?

我不是这方面的专家,但我注意到您可以使用 .NET 运行时的性能计数器来监视一些有趣的事情——其中之一是垃圾分配的字节数最后 collection 期间的收藏家。 Performance Counters in the .NET FrameworkAllocated Bytes/second 的描述指出:

Displays the number of bytes per second allocated on the garbage collection heap. This counter is updated at the end of every garbage collection, not at each allocation. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.

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

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

更新(感谢 Thomas)

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

这应该有效,因为如果没有垃圾 collection 发生,该值仅为零。

如果您不是在英文版操作系统上运行,则必须找出性能计数器的正确语言特定名称(可以通过查看上面提供的 MSDN-link 并切换到那里的另一种语言)。例如。德国名字会 成为 "\.NET CLR-Speicher(ProcessName)\Zugeordnete Bytes/Sek.".