【问题标题】:How to find the source of a StackOverflowException in my application如何在我的应用程序中找到 StackOverflowException 的来源
【发布时间】:2013-09-14 08:03:17
【问题描述】:

我的应用程序中某处发生了 StackOverFlow - 我正在尝试找出跟踪它的方法。

我的事件日志每天都会显示崩溃,并包含以下信息:

错误应用程序名称:MyApp.exe,版本:1.0.0.0,时间戳:0x522e8317

故障模块名称:clr.dll,版本:4.0.30319.18047,时间戳:0x515530ce

异常代码:0xc00000fd

故障偏移:0x000000000000c657

故障进程ID:0x117fc

错误的应用程序启动时间:0x01ceadf607b184d2

错误的应用程序路径:C:\Users\Administrator\Desktop\MyApp.exe

错误模块路径:C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll

报告 ID:d52424aa-1a16-11e3-bc4b-002590a4ec55

我读到 0xc00000fd 是堆栈溢出,但我不确定它可能发生在哪里(非常大的代码库),以及如何追踪它。有什么想法吗?

【问题讨论】:

  • 你还有其他的 - 应用程序级别 - 日志记录吗?
  • 我的第一个猜测是某些导致无限循环或大量递归的条件。
  • 这可能会很痛苦,但您可以尝试手动遍历每个 forwhile 和任何其他循环,以确保它们最终退出。
  • 关于循环 cmets:无限循环很可能永远不会导致堆栈溢出。递归几乎肯定是原因。
  • 使用 WinDbg + SOS 是确定正在发生的事情的最简单方法。设置 ADPlus 以在您的进程崩溃时进行小型转储,并检查转储以查看发生了什么。

标签: c# .net


【解决方案1】:

这通常是我使用 WinDbg 来追踪的,否则它只是一个猜谜游戏。下面是一个快速演练,应该可以为您指明正确的方向。

WinDbg 是适用于 Windows 的调试器,适用于调试托管和非托管代码。它也非常适合检查故障转储。让我们从一个示例程序开始。

class Program
{
    static void Main(string[] args)
    {
        IWillStackOverflow(0);
    }

    [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
    static int IWillStackOverflow(int i)
    {
        return IWillStackOverflow(i + 1);
    }
}

这是一个非常人为的例子,但让我们继续吧。它确实堆栈溢出,也没有提供堆栈跟踪。这就是 WinDbg 的用武之地。首先您需要安装它,它是 Windows SDK 中调试工具的一部分。有两个版本,x64 和 x86。您需要运行与您的应用程序位数相匹配的那个。

在 WinDbg 中,使用 File -> Open Executable 并运行附加了 WinDbg 的可执行文件。一旦您的应用程序加载,调试器就会中断,您可以使用g 命令转到并使用您的应用程序,直到您收到 StackOverflowException。不过,在你这样做之前,请确保你的符号是正确的 - 通常运行 .symfix+ 会更正它,然后你就可以走了。

当您收到 StackOverflowException 时,调试器将在引发异常的线程上中断,消息将如下所示:

(cc0.b00):堆栈溢出 - 代码 c00000fd(第一次机会)

现在我们可以使用此命令加载托管调试扩展(我假设您使用的是 .NET Framework 4.0 或 4.5):

.loadby sos clr

并致电!clrstack。在本例中,输出为:

000000d440c76040 00007ffb282b0111 StackOverflower.Program.IWillStackOverflow(Int32) [Program.cs @ 20]
000000d440c76080 00007ffb282b0111 StackOverflower.Program.IWillStackOverflow(Int32) [Program.cs @ 20]
000000d440c760c0 00007ffb282b0111 StackOverflower.Program.IWillStackOverflow(Int32) [Program.cs @ 20]
..Repeat thousands of times..

所以我们在 StackOverflowException 发生时拥有托管堆栈。

如果您的应用程序不太容易 StackOverflow,您可以配置 ADPlus 以在 StackOverflowException 发生时对您的应用程序进行内存转储。 ADPlus 是另一个重磅工具,但它很有效。首先你需要一个 ADPlus 的配置,这里是一个例子:

<ADPlus> 
   <!-- Add log entry, log faulting thread stack and dump full on first chance StackOverflow --> 
<Exceptions> 
     <Config> 
        <!-- Use sov for stack overflow exception --> 
       <Code> sov </Code> 
       <Actions1> Log;Stack;FullDump </Actions1> 
       <!-- Depending on what you intend - either stop the debugger (Q or QQ) or continue unhandled (GN) --> 
       <ReturnAction1> GN </ReturnAction1> 
     < Config> 
  </Exceptions> 
</ADPlus>

此配置示例最初由用户 jaskis 在 MSDN 论坛上发布:http://blogs.msdn.com/b/jaskis/archive/2010/08/11/cwa-ends-up-with-blank-screen-on-browser-on-iis-7.aspx 然后使用命令行使用配置启动您的应用程序。


这只是一个例子,WinDbg 是一个非常强大的工具,虽然它有一点学习曲线。互联网上有很多很好的资源来掌握它。 Tess Ferrandez 在她的博客中有很多关于 WinDbg 和托管调试扩展的文章。

【讨论】:

  • 我希望你能把你的评论变成一个答案,我也不想自己写这个:)。唯一缺少的是如何设置崩溃时程序的小型转储以及如何将其加载到 WinDbg 而不是在调试器中运行程序,OP 说它每天崩溃一次,所以调试器必须是贴了好久才看到。
  • 为了进一步阅读,我发现 this blog posting 可以让您的 C# 代码在崩溃时生成转储以及如何在 WinDbg 中打开它
  • @ScottChamberlain 我添加了一些关于 ADPlus 的信息,希望足够有用。感谢您的反馈。
  • 感谢您的回答。我不得不根据MSDN 调整 sos 加载并确保我以管理员身份运行,但这一切都使我能够深入了解我的 EF SO 错误:-)
【解决方案2】:

这已经得到解答,但我在受影响的机器上寻找比WinDbg 更好的答案,因为这仅发生在我不想安装WinDbg 的生产服务器机器上。我找到了this article,它指的是微软的一个可下载工具,它允许您基于每个异常代码配置系统应如何响应不同的异常。这将(希望)允许在与生产机器不同的机器上进行调试:

DebugDiag 实用程序可以配置为在StackOverflowException 发生时生成故障转储。下载here.

【讨论】:

  • 谢谢!我能够从 VS 的 Debug 菜单中保存转储文件,然后使用 DebugDiag 对其进行分析,并在第 3 方库中找到堆栈溢出异常的来源。
猜你喜欢
  • 1970-01-01
  • 2013-11-17
  • 1970-01-01
  • 1970-01-01
  • 2012-05-20
  • 1970-01-01
  • 1970-01-01
  • 2011-07-19
  • 1970-01-01
相关资源
最近更新 更多