【问题标题】:I've found a bug in the JIT/CLR - now how do I debug or reproduce it?我在 JIT/CLR 中发现了一个错误 - 现在我该如何调试或重现它?
【发布时间】:2012-09-17 09:44:25
【问题描述】:

我有一个计算量很大的多线程 C# 应用程序,它似乎在运行 30-90 分钟后一直崩溃。它给出的错误是

运行时遇到致命错误。错误地址位于线程 0xbcc 上的 0xec37ebae。错误代码为 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"

【问题讨论】:

  • 你确定不是你的电脑内存问题?当指针损坏并设置为无效的内存位置时,我在其他程序中看到了相同的错误代码。
  • @Matthew:我将运行一些内存测试,并尝试在另一台机器上重现它。但我对此表示怀疑 - 该程序不是很占用内存,而且我对任何其他程序都没有任何问题。此外,它总是在同一行崩溃。
  • 我不熟悉 CLR,但是在 Sun JVM 上,有一个标志可以记录所有已编译的方法——如果您可以确定 (1) 是否调用了 JIT,这可能会有所帮助,以及 (2) 崩溃发生后多长时间。可能有一个工具可以让您检查内存映射以找出在该地址加载的内容(甚至是否在代码块中)。
  • @AlexeiLevenkov:详细说明如何执行这些技巧和类似技巧的答案正是我想要的。
  • @BlueRaja-DannyPflughoeft 您能否回答 Jon 的一些问题:例如,您是否能够在另一台机器上复制?您可以在更新当前 PC 上的所有内容后重现吗?你能轻松地复制它吗(即即使需要 90 分钟也可以按需复制)?如果其中任何一个的答案是“是”,那么您应该通过 WinDbg 启动您的进程,该进程将在您的应用退出(崩溃)之前中断,这样您就可以看到发生了什么

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


【解决方案1】:

tl;dr 确保您正在编译为 .Net 4.5


这听起来很像 here 发现的相同错误。来自MSDN page

垃圾收集器在释放和压缩内存时可能会遇到此错误。当启用并发垃圾收集并且发生前台垃圾收集和后台垃圾收集的某种组合时,可能会发生该错误。当这种情况发生时,您将一遍又一遍地看到相同的调用堆栈。在堆上你会看到一个空闲对象,在它结束之前你会看到另一个空闲对象破坏了堆。

修复方法是编译为 .Net 4.5。如果由于某种原因你不能这样做,你也可以通过在app.config 文件中禁用gcConcurrentdisable concurrent garbage collection

<configuration>
   <runtime>
       <gcConcurrent enabled="false"/>
   </runtime>
</configuration>

或者直接编译成x86

【讨论】:

    【解决方案2】:

    我建议您立即通过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

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

    【讨论】:

      【解决方案3】:

      下载Debug Diagnostic Tool v1.2

      1. 运行程序
      2. 添加规则“崩溃”
      3. 选择“具体流程”
      4. 在页面高级配置上,如果您知道在哪个异常上失败,或者只保留此页面原样,请设置您的异常
      5. 设置用户转储位置

      现在等待进程崩溃,DebugDiag 创建日志文件。现在激活选项卡Advanced Analysis,在顶部列表中选择Crash/Hang Analyzers,在下方列表中选择dump file,然后点击Start Analysis。这将为您生成 html 报告。希望您在该报告中找到有用的信息。如果您在分析时遇到问题,请将 html 报告上传到某处并将 url 放在这里,以便我们专注于它。

      【讨论】:

        【解决方案4】:
        • 您是否对您的机器进行了内存测试,因为有一次我有类似的症状,我的一个调光器出现故障(Win7 中包含一个非常好的内存测试器;http://www.tomstricks.com/how-to-test-your-ram-or-memory-with-windows-memory-diagnostic-tool-in-windows-7/

        • 如果您的 CPU 在这段时间后过热,也可能是加热/节流问题。虽然这会更快发生恕我直言。

        • 应该有一个可以分析的转储文件。如果您从未这样做过,请找到这样做的人,或将其发送给 microsoft

        【讨论】:

        • 有转储文件,这不是硬件问题 - 我可以在其他几台机器上重现它。
        【解决方案5】:

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

        您可能会这么想,但是线程、通过信号量进行同步、互斥以及任何句柄都是本机的。 .net 是操作系统的一个层,.net 本身不支持多线程应用程序的纯 clr 代码,这是因为 OS 已经做到了。

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

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

        您有以下两种选择,

        1. 发布您的代码,以便我们检查瓶颈
        2. 使用 .net 并行线程框架重新设计您的应用程序,其中包括需要 CPU 密集型操作的各种算法。

        随着集合的增长和操作在其他线程干扰之前无法执行,很可能程序会在一段时间后失败。例如生产者消费者问题,直到生产者变慢或在消费者启动之前无法完成其操作,您才会注意到任何问题。

        clr 中的错误很少见,因为 clr 非常稳定。但是写得不好的代码可能会导致错误在 clr 中显示为 bug。 Clr 不能也永远不会检测到错误是在您的代码中还是在 clr 本身中。

        【讨论】:

        • “使用 .net 并行线程框架重新设计您的应用程序” - 这就是它所使用的......
        • 如果您将发布一些内部代码,那么我们可以提供更多指导。
        • 我强烈建议先查看多线程问题。这很可能会导致内存损坏。这实际上会为进行复制提供一个很好的起点,创建一个执行大量常见计算的多线程应用程序。
        【解决方案6】:

        我想弄清楚是什么原因造成的,或者至少写一个较小的复制品发送给微软,但我什至不知道从哪里开始。

        “更小的复制”在这里听起来绝对是个好主意......即使“更小”并不意味着“更快地复制”。

        在开始之前,请尝试在另一台机器上重现错误。如果您无法在另一台机器上重现它,则表明需要进行一组完全不同的测试 - 硬件、安装等。

        另外,请检查您是否使用了所有内容的最新版本。花几天时间调试它会很烦人(这很可能,我担心)然后最终得到一个响应“是的,我们知道这一点 - 这是 .NET 4 中的一个错误,已在 .NET 4.5 中修复“ 例如。如果你能在各种框架版本上重现它,那就更好了:)

        接下来,将程序中的所有内容都删掉:

        • 它有用户界面吗?如果可能,请将其删除。
        • 它是否使用数据库?看看您是否可以删除所有数据库访问:绝对是以后不使用的任何输出,理想情况下也是输入。如果您可以在应用程序中对输入进行硬编码,那将是理想的选择 - 但如果不能,则复制文件比访问数据库更简单。
        • 它对数据敏感吗?同样,如果不了解应用程序,很难知道这是否有用,但假设它处理大量数据,您能否使用二进制搜索来查找导致问题的相对少量数据?
        • 必须是多线程的吗?如果您可以删除所有线程,显然这可能需要更长的时间来重现问题 - 但它仍然会发生吗?
        • 尝试删除一些业务逻辑:如果您的应用程序被适当地组件化,您可能可以通过首先创建一个存根实现,然后简单地删除调用来伪造整个重要组件。

        所有这些都会逐渐减小应用程序的大小,直到它更易于管理。在每一步,您都需要再次运行该应用程序,直到它崩溃或您确信它不会崩溃。如果您有很多可用的机器,那应该会有所帮助...

        【讨论】:

        • 只是一个更新:它出现在ponsfonze found my problem。当然,这是 .Net 4.5 中修复的问题......我应该听你的!
        【解决方案7】:
        猜你喜欢
        • 2014-02-19
        • 2011-04-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-09
        • 2020-02-17
        • 1970-01-01
        相关资源
        最近更新 更多