情境:
我刚刚开始使用并实现了一堆代码,但是当我执行它时,我会抛出一个StackOverflowException? StackOverflowException没有堆栈跟踪,所以我卡住了。我知道为什么会发生堆栈溢出,但要修复它我需要知道它的根目录是什么。
所有我得到的是:tag-you-it.dll中出现未处理的“System.StackOverflowException”类型异常
选项:
PS:
这是一种假设情况(尽管并不常见),因此没有可用的代码。
答案 0 :(得分:16)
这几乎总是归因于递归。一个调用自身的方法,或一个调用一个方法来调用它的方法,等等。
找到它:
StackOverflowException
的堆栈跟踪(我猜想无法捕获一个跟踪,无论是)。但是有一些方法可以获得转储as mentioned here。偶尔你会得到这样的拼写错误:
private string name;
public string Name
{
get { return Name; } // Ooops! This is recursive, all because of a typo...
}
这就是我个人现在更喜欢使用自动属性的原因之一。
答案 1 :(得分:11)
WinDbg可以完成工作,甚至包括获得合理的(clr)堆栈跟踪。 您需要get WinDbg,除非您已经使用Visual Studio或Windows SDK安装它。 注意:使用新GUI的“WinDbg预览”对我来说很好。
我建议您从WinDbg开始您的流程,但当然如果这更适合您,您也可以将其附加到正在运行的流程中。
注意:在启动进程后,CLR未加载,.loadby SOS.dll clr
将失败(“无法找到模块'clr')。您必须等待加载CLR。停止执行一旦发生这种情况,执行:
sxe ld clr
加载CLR后,您必须执行以下步骤以中断SackOverflowException
(在命令窗口/行中输入):
.loadby SOS.dll clr
(不 .loadby sos clr
- 这可能会导致扩展程序被加载两次)!stoponexception -create System.StackOverflowException
g
(继续调试)触发StackOverflowException /等待它发生
!clrstack
(将打印堆栈跟踪)值得注意的消息来源:
答案 2 :(得分:8)
转到Debug,exception并检查'Common Language Runtime Exceptions'中的抛出复选框。现在,当您导致stackoverflow异常时,调试器将停止(最终)并显示调用堆栈。
答案 3 :(得分:5)
您可以在调试模式下执行程序并暂停它。在当前的callstack上,你可以看到有一种方法或一组方法多次出现,这些都是有问题的方法。在这个方法上加上一个断点,看看它一直在调用它自己。
答案 4 :(得分:1)
在作为失败操作的“入口点”的方法中,放置一个断点。逐步执行代码并观察以相同模式反复发生的相同方法调用序列的出现,以便调用堆栈越来越深。
一旦你注意到,就把断点放在当前位置,无论在哪里。继续执行(Visual Studio中的F5) - 如果你在正确的轨道上,那么调试器将在同一位置快速停止,并且调用堆栈将更深。
现在你可以检查一个“实时”堆栈框架,以便弄清楚如何确保这种递归正确终止。
答案 5 :(得分:1)
ProcDump实用程序帮助我们将问题调试为described in details here。步骤:
procdump -accepteula -e 1 -f C00000FD.STACK_OVERFLOW -g -ma <process ID> d:\home\DebugTools\Dumps
(目录必须存在)来附加调试器我们可以通过启用 CrashDiagnoser 扩展名(例如described here)在Azure上使用相同的技术。基本上,它执行与上述相同的步骤。它生成的转储文件可以在Visual Studio中下载并打开。
答案 6 :(得分:0)
如果您有代码并且能够从Visual Studio运行程序,它应该在遇到System.StackOverflowException时中断调试器(如果启用了第一次机会异常)。从那里你可以检查调用堆栈,看看哪些调用正在吹动堆栈。
我已经确认这适用于Visual Studio 2010和Visual C#2010 Express。
答案 7 :(得分:0)
就个人而言,我希望尽可能地将其缩小到某段代码。例如,我只有一个。奇怪的是它只发生在我无法直接调试的机器上。
我有两个并行运行的线程,所以我阻止了一个运行(或者你可以将它无法并行)。
然后我浏览了我的函数并添加了类似打印输出的函数,例如: 就像功能开始一样:
Console.WriteLine("<Enter method: {0}", DebuggingHelper.GetCurrentMethod());
在函数返回之前:
Console.WriteLine(">Exit method: {0}", DebuggingHelper.GetCurrentMethod());
将GetCurrentMethod定义为:
[MethodImpl(MethodImplOptions.NoInlining)]
public static string GetCurrentMethod()
{
StackTrace st = new StackTrace();
StackFrame sf = st.GetFrame(1);
return sf.GetMethod().Name;
}
然后我运行它,也许我不添加所有功能,但足以缩小它在代码中发生的位置。然后在该部分中添加更多。
您还可以在运行某些方法时添加检查点。
然后再次运行它,你会发现在这些语句之间会发生StackOverFlow异常。继续缩小直到你找到它。
通过这种方式非常简单快速地找到它发生的位置。
答案 8 :(得分:0)
只是想添加有关使用WinDbg的答案,以及我发现的用于调试 dotnet核心应用程序的信息
.loadby sos coreclr
(这将检测到您正在使用的.net core的版本,但是如果没有,则可以使用.load C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\sos
,其中2.05是您正在使用的.netcore的版本。 !help
使用!dso
获取堆栈的转储在我的情况下,我确切地知道了stackoverflow异常发生的位置
答案 9 :(得分:0)
我怀疑导致堆栈溢出的线程的堆栈大小是否大于Visual Studio调试器可以跟踪的某个阈值,那么调用堆栈不可用。
一种解决方法是生成一个堆栈大小小于默认堆栈大小的线程,因此Visual Studio调试器可以跟踪调用堆栈。
(new Thread(delegate ()
{
ProduceAStackOverFlowHere() ;
}, 256 * 1024)).Start();//Default size for 32 bit process is 1MB, 64 bit process is 4MB. So I'll set the size at 256KB.
答案 10 :(得分:0)
在 IKVM.MET 的开发过程中,我想出了一个技巧来调试静态和动态程序集中的堆栈溢出错误,因为 IKVM.NET 广泛使用了动态程序集。我将在 Visual Studio 调试器中运行可执行文件,当发生堆栈溢出时,Visual Studio 调试器将挂起该进程,而不是终止它。然后,我使用 dotnet-dump 获取核心转储,最后,我将终止进程以释放 RAM 并使用 dotnet-dump 分析核心转储。请注意,这仅适用于 .NET 核心应用程序。
创建核心转储的命令
dotnet-dump collect -p <Process ID here>
可以使用任务管理器获取进程 ID。 查看堆栈跟踪的命令:
dotnet-dump analyze <file name of dump> -c clrstack -all
How to use dotnet-dump, if you want to do further debugging
注意:这种调试技术有风险,因为该进程可能会被破坏,并且可能无法每次都运行。
答案 11 :(得分:-1)
查找调用自身的方法(或一种方法调用另一种方法,反之亦然)并检查它们。当您获得SO异常时,递归通常是主要的嫌疑。