我有一个计算成本高昂的多线程C#应用程序,在运行30-90分钟后似乎一直崩溃。它给出的错误是
运行时遇到了致命错误。错误的地址是0xec37ebae,在线程0xbcc上。错误代码是0xc0000005。此错误可能是CLR中的错误,也可能是用户代码的不安全或不可验证部分中的错误。此错误的常见来源包括COM-interop或PInvoke的用户封送错误,这可能会破坏堆栈。
(0xc0000005是Access Violation的错误代码)
我的应用不会调用任何本机代码,也不会使用任何不安全的块,甚至不会使用任何非CLS兼容的类型,例如uint
。实际上,调试器所说的导致崩溃的代码行是
overallLength += distanceTravelled;
其中两个值均为double
鉴于这一切,我认为崩溃必定是由于编译器或CLR或JIT中的错误造成的。我想找出导致它的原因,或者至少写一个较小的复制品发送到微软,但我不知道从哪里开始。我从来没有必要查看CIL二进制文件,或编译的JIT输出,或本机堆栈跟踪(崩溃时没有托管堆栈跟踪),所以我不知道如何。我甚至无法弄清楚如何在崩溃时查看所有变量的状态(不幸的是,VS在管理异常之后不会告诉我它,并将它们输出到控制台/文件会将应用程序放慢1000倍,这显然不是一个选项)。
那么,我该如何调试呢?
[编辑] 在VS 2010 SP1下编译,运行最新版本的.Net 4.0 Client Profile。显然它是“。Net 4.0C / .Net 4.0E,.Net CLR 1.1.4322”
答案 0 :(得分:22)
我想知道是什么导致它,或者至少写一个较小的复制品发送到微软,但我不知道从哪里开始。
“较小的复制”在这里听起来确实是一个好主意......即使“较小”并不意味着“更快地再现”。
在开始之前,尝试在另一台计算机上重现错误。如果你不能在另一台机器上重现它,那就建议做一整套不同的测试 - 硬件,安装等。
另外,检查一下你所有的最新版本。花这些时间来调试它(这很可能,我很害怕)然后最终得到“是的,我们知道这个 - 这是.NET 4中的一个错误,它已经在.NET 4.5中得到修复“ 例如。如果你可以在各种框架版本上重现它,那就更好了:)
接下来,删除程序中的所有内容:
所有这些都将逐渐减小应用程序的大小,直到它更易于管理。在每一步,您都需要再次运行应用程序,直到它崩溃或您确信它不会崩溃。如果您有很多可用的机器,那应该有帮助...
答案 1 :(得分:10)
tl; dr 确保您正在编译为.Net 4.5
这听起来像发现here的错误一样可疑。来自MSDN page:
当垃圾收集器释放并压缩内存时,可能会遇到此错误。启用“并发垃圾收集”并发生前景垃圾收集和后台垃圾收集的某种组合时,可能会发生此错误。发生这种情况时,您将反复看到相同的调用堆栈。在堆上,您将看到一个自由对象,在它结束之前,您将看到另一个自由对象破坏堆。
修复是编译到.Net 4.5。如果由于某种原因您无法执行此操作,您还可以disable concurrent garbage collection禁用gcConcurrent
文件中的app.config
:
<configuration>
<runtime>
<gcConcurrent enabled="false"/>
</runtime>
</configuration>
或者只是编译到x86
。
答案 2 :(得分:9)
WinDbg是你的朋友:
答案 3 :(得分:6)
现在等待进程崩溃,DebugDiag创建日志文件。现在激活选项卡 Advanced Analysis ,在顶部列表中选择Crash / Hang Analyzers并在下方列表中转储文件,然后点击 Start Analysis 。这将为您生成HTML报告。希望您在该报告中找到有用的信息。如果您在分析时遇到问题,请在某处上传html报告并将网址放在此处,以便我们专注于此。
答案 4 :(得分:4)
我的应用不会调用任何本机代码,也不会使用任何不安全的块,或者 甚至任何非符合CLS的类型,如uint
你可能会想到这一点,但是线程化,通过信号量同步,互斥它任何处理都是原生的。 .net是一个操作系统层,.net本身不支持多线程应用程序的纯clr代码,这是因为操作系统已经完成了。
这很可能是线程同步错误。可能多个线程正在尝试访问clr边界之外的共享资源,如文件等。
您可能认为您没有访问com等,但是当您调用某些API(例如获取桌面文件夹路径等)时,它将通过shell com API调用。
您有以下两个选项,
很可能程序在一段时间后失败,因为集合长大,操作在其他线程干扰之前无法执行。例如,生产者消费者问题,你不会发现任何问题,直到生产者变得更慢或无法在消费者开始之前完成其操作。
clr中的bug很少见,因为clr非常稳定。但编写得不好的代码可能会导致错误在clr中显示为bug。 Clr不能并且永远不会检测到错误是在您的代码中还是在clr本身中。
答案 5 :(得分:1)
你有没有为你的机器进行内存测试,因为有一次我有类似的症状,我的一个dimms被证明是有缺陷的(Win7中包含了一个非常好的记忆测试器; http://www.tomstricks.com/how-to-test-your-ram-or-memory-with-windows-memory-diagnostic-tool-in-windows-7/)
如果您的CPU在这段时间后过热,这也可能是加热/限制问题。虽然那会很快发生。
应该有一个可以分析的转储文件。如果您从未这样做过,请找一个做过的人,或者将其发送到microsoft
答案 6 :(得分:0)
我建议您立即通过http://support.microsoft.com打开支持案例,因为支持人员可以向您展示如何收集必要的信息。
一般来说,像@ paulsm4和@psulek所说,你可以利用WinDbg或Debug Diag来捕获进程的崩溃转储,并在其中嵌入所有必要的信息。但是,如果这是您第一次使用这些工具,您可能会感到困惑。 Microsoft支持团队可以为您提供分步指导,或者他们甚至可以与您建立Live Meeting会话以捕获数据,因为程序经常崩溃。
熟悉这些工具后,您可以更轻松地执行类似的故障排除,
顺便说一句,现在说“我发现了一个错误”还为时过早。虽然您无法在程序中找到对本机代码的依赖,但它仍可能依赖于本机代码。在进一步调试问题之前,我们不应该得出结论。