【发布时间】:2013-01-09 15:28:16
【问题描述】:
我正在尝试调试一些处理大文件的工作。代码本身工作,但 .NET 运行时本身报告了零星错误。就上下文而言,这里的处理是一个 1.5GB 的文件(仅加载到内存中一次)被循环处理和释放,故意尝试重现这个不可预测的错误。
我的测试片段基本上是:
try {
byte[] data =File.ReadAllBytes(path);
for(int i = 0 ; i < 500 ; i++)
{
ProcessTheData(data); // deserialize and validate
// force collection, for tidiness
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
}
} catch(Exception ex) {
Console.WriteLine(ex.Message);
// some more logging; StackTrace, recursive InnerException, etc
}
(加上一些时间和其他东西)
对于不确定的迭代次数,循环将很好地处理完全成功 - 没有任何问题;然后该过程将突然终止。异常处理程序未命中。该测试确实涉及大量内存使用,但它在每次迭代期间都非常好(没有明显的内存泄漏,而且我有足够的空间 - 14GB 未使用的主内存在最差锯齿中的点)。该进程是 64 位的。
Windows 错误日志包含 3 个新条目,其中(通过退出代码 80131506)表明执行引擎错误 - 一个讨厌的小动物。 related answer,表示 GC 错误,带有“修复”以禁用并发 GC;但是这个“修复”并不能阻止这个问题。
澄清:此低级错误不会触发CurrentDomain.UnhandledException 事件。
澄清:GC.Collect 仅用于监视锯齿状内存,检查内存泄漏并保持可预测性;删除它并不会解决问题:它只是让它在迭代之间保留更多内存,并使 dmp 文件更大;p
通过添加更多控制台跟踪,我观察到它在每个过程中都出现故障:
- 反序列化期间(大量分配等)
- 在 GC 期间(在 GC“方法”和 GC“完成”之间,使用 GC 通知 API)
- 在验证期间(只是
foreach处理一些数据) - 奇怪的是就在在验证期间 GC“完成”之后
这么多不同的场景。
我可以获得故障转储(dmp)文件;我该如何进一步调查这个问题,看看系统在发生如此严重的故障时在做什么?
【问题讨论】:
-
很好奇为什么要显式调用 GC,因为在极少数情况下可以将其视为良好做法。鉴于您的代表,我相信您有充分的理由并很好奇它是什么。
-
@EricJ 这不是生产代码; GC 收集只是为了让每次迭代都进入已知状态,而不是在中间随机进行 GC。删除它并不能修复错误:它只会让观察锯齿变得更加困难;p 这整个代码块的存在纯粹是为了对此进行压力测试,以重现报告的错误。
-
不确定是否相关,但根据MSDN,垃圾收集器在重负载下会产生此错误:
In some cases, an application that targets the .NET Framework may throw an ExecutionEngineException exception during garbage collection when an application or the system on which it is running is under a heavy load. As a workaround, you can disable concurrent garbage collection by modifying the application's configuration file. For more information, see How to: Disable Concurrent Garbage Collection. -
您是否设法找出造成这种情况的原因?
-
@Nahum 当我问这个问题时,它是通过支持电子邮件发送给我的一个开源项目的,我可以在本地复制。我们似乎不太可能遇到完全相同的 RAM 故障。