我在JIT / CLR中发现了一个错误 - 现在我该如何调试或重现它?

时间:2012-09-25 20:10:32

标签: c# .net debugging compiler-errors jit

我有一个计算成本高昂的多线程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”

7 个答案:

答案 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)

答案 3 :(得分:6)

下载Debug Diagnostic Tool v1.2

  1. 运行程序
  2. 添加规则“崩溃”
  3. 选择“特定流程”
  4. 在页面上高级配置设置您的例外,如果您知道它失败的例外,或者只是按原样保留此页面
  5. 设置用户转储位置
  6. 现在等待进程崩溃,DebugDiag创建日志文件。现在激活选项卡 Advanced Analysis ,在顶部列表中选择Crash / Hang Analyzers并在下方列表中转储文件,然后点击 Start Analysis 。这将为您生成HTML报告。希望您在该报告中找到有用的信息。如果您在分析时遇到问题,请在某处上传html报告并将网址放在此处,以便我们专注于此。

答案 4 :(得分:4)

  

我的应用不会调用任何本机代码,也不会使用任何不安全的块,或者   甚至任何非符合CLS的类型,如uint

你可能会想到这一点,但是线程化,通过信号量同步,互斥它任何处理都是原生的。 .net是一个操作系统层,.net本身不支持多线程应用程序的纯clr代码,这是因为操作系统已经完成了。

这很可能是线程同步错误。可能多个线程正在尝试访问clr边界之外的共享资源,如文件等。

您可能认为您没有访问com等,但是当您调用某些API(例如获取桌面文件夹路径等)时,它将通过shell com API调用。

您有以下两个选项,

  1. 发布您的代码,以便我们查看瓶颈
  2. 使用.net并行线程框架重新设计您的应用程序,其中包括需要CPU密集型操作的各种算法。
  3. 很可能程序在一段时间后失败,因为集合长大,操作在其他线程干扰之前无法执行。例如,生产者消费者问题,你不会发现任何问题,直到生产者变得更慢或无法在消费者开始之前完成其操作。

    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会话以捕获数据,因为程序经常崩溃。

熟悉这些工具后,您可以更轻松地执行类似的故障排除,

http://blogs.msdn.com/b/lexli/archive/2009/08/23/when-the-application-program-crashes-on-windows.aspx

顺便说一句,现在说“我发现了一个错误”还为时过早。虽然您无法在程序中找到对本机代码的依赖,但它仍可能依赖于本机代码。在进一步调试问题之前,我们不应该得出结论。