25

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

运行时遇到致命错误。错误地址位于线程 0xbcc 上的 0xec37ebae。错误代码为 0xc0000005。此错误可能是 CLR 中的错​​误或用户代码的不安全或不可验证部分中的错误。此错误的常见来源包括 COM 互操作或 PInvoke 的用户封送错误,这可能会损坏堆栈。

(0xc0000005 是Access Violation的错误代码)

我的应用程序不调用任何本机代码,也不使用任何不安全的块,甚至不使用任何不符合 CLS 的类型,例如uint. 事实上,调试器所说的导致崩溃的代码行是

overallLength += distanceTravelled;

两个值都是类型double


鉴于这一切,我认为崩溃一定是由于编译器或 CLR 或 JIT 中的错误。我想弄清楚是什么原因造成的,或者至少写一个较小的复制品发送给微软,但我什至不知道从哪里开始。我从来不需要查看 CIL 二进制文件、编译的 JIT 输出或本机堆栈跟踪(崩溃时没有托管堆栈跟踪),所以我不确定如何。我什至不知道如何在崩溃时查看所有变量的状态(不幸的是,VS 不会像在托管异常之后那样告诉我,并且将它们输出到控制台/文件会减慢app 1000 倍,这显然不是一个选项)

那么,我该如何调试呢?


[编辑]在 VS 2010 SP1 下编译,运行最新版本的 .Net 4.0 Client Profile。显然它是“.Net 4.0C/.Net 4.0E,.Net CLR 1.1.4322”

4

7 回答 7

23

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

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

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

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

接下来,删除程序中的所有内容:

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

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

于 2012-10-01T05:58:21.013 回答
10

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


这听起来很像这里发现的相同错误。从MSDN 页面

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

修复方法是编译为 .Net 4.5。如果由于某种原因你不能这样做,你也可以通过在文件中禁用来禁用并发垃圾回收:gcConcurrentapp.config

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

或者只是编译为x86.

于 2012-12-22T07:55:45.343 回答
6

下载调试诊断工具 v1.2

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

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

于 2012-10-05T13:35:02.050 回答
4

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

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

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

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

您有以下两种选择,

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

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

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

于 2012-10-01T06:21:55.240 回答
1
  • 你有没有对你的机器进行内存测试,因为有一次我有类似的症状,我的一个调光器出现了故障(Win7 中包含一个非常好的内存测试器;http://www.tomstricks.com/how-to-用 Windows 内存诊断工具在 Windows 7/ 中测试你的内存或内存

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

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

于 2012-10-01T06:27:13.903 回答
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

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

于 2012-10-06T02:31:22.760 回答