如何在我的WinForm应用程序中调试StackOverflowException?

3
我有一个Winform应用程序。每隔几秒钟,我会检查一些日志文件,读取任何新数据,并将任何新数据插入到数据库中。
当我运行应用程序约1个半小时时,我会收到一个StackOverflowException异常。在整个时间段内,日志文件中没有新数据,因此没有添加任何新数据到数据库中。
代码出错的地方是...
if (pictureBox == null)
{
    continue;
}

if (pictureBox.InvokeRequired)
{
    var toolTip = new ToolTip();
    GameServer tempGameFile = gameServer;
    pictureBox.Invoke(new MethodInvoker(
        () => toolTip.SetToolTip(pictureBox,
            string.Format(
                "{0} : Last Checked: {1}; Last Updated: {2}",
                tempGameFile.Name,
                tempGameFile.CheckedOn.ToLongTimeString(),
                tempGameFile.UpdatedOn.HasValue
                    ?
                        tempGameFile.UpdatedOn.Value.ToLongTimeString()
                        : "-No Date Set-"))));
}
pictureBox.Image = Resources.RedButton;

“pictureBox.Invoke(..)”引发了该错误。

所以,我不确定如何调试以找出问题所在?有什么建议吗?

更新

尝试Dmitry的建议后,我启动了ANTS分析器内存剖面图,并快速查看了一下,似乎有很多ToolTip控件的实例。

这是20分钟后的类列表摘要。

enter image description here

许多事件处理程序(我是否没有释放某些内容?)

还有一些工具提示...

这是所有实例的屏幕截图这是单个工具提示控件图/地图的屏幕截图.. 我不知道如何阅读害羞


触发发布的代码是什么?它没有包含方法签名,也不清楚,至少对我来说不清楚。 - Samuel Neff
2
这段代码放在哪个事件中? - jgauffin
我已经成功运行了应用程序..需要再等待一个小时左右,才会抛出SOE :( 现在..那段代码放在哪个事件中?它是在GameServersParsingBackgroundWorker_DoWork方法内被调用的..一个BackgroundWorker进程。 - Pure.Krome
很难想象这会导致SO错误。你的代码中是否有嵌套的事件处理程序和/或其他地方的Application.DoEvents()?错误出现在这里并不意味着它是由此引起的。 - H H
如上所述,您需要做的第一件事是在异常发生时获取堆栈跟踪。 - Andrew Savinykh
显示剩余2条评论
2个回答

4
您的代码存在两个潜在问题: var toolTip = new ToolTip();pictureBox.Image = Resources.RedButton; 都在非UI线程上调用。我必须使用Control.Invoke将该代码转换为UI线程。如果修复此问题无效,请查看我的答案以了解如何在Windows服务中调试StackOverflowException。
更新:请尝试此代码。请注意,引用任何UI控件的每个语句都需要使用Control.Invoke进行编组:
if (pictureBox == null || !pictureBox.IsHandleCreated) {
    continue;
}

Action setTooltipAndImage = () => {
    var toolTip = new ToolTip();
    GameServer tempGameFile = gameServer;
    toolTip.SetToolTip(pictureBox, string.Format(...));
    pictureBox.Image = Resources.RedButton;
};

if (pictureBox.InvokeRequired) {                        
    pictureBox.Invoke(setTooltipAndImage);
} else {
    setTooltipAndImage();
}

阅读从线程中操作控件可能会很有价值。


所以我需要同时“调用”它们吗?现在我正在为“SetToolTip”这样做...但这还不够吗?你能提供一些示例代码吗?你说得对,我正在从后台线程访问这些UI元素。 - Pure.Krome
访问已修改的闭包:GameServer tempGameFile = gameServer;,因此我在 Action setToolTipAndImage ... 代码上方制作了一个临时副本。即 var tempGameServer = gameserver; Action setToolTipAndImage ... 此外,我的原始代码没有调用所有带有工具提示的内容,所以我需要调用 newSetToolTipResources.RedButton。明白了。 - Pure.Krome
我正在运行ANTS内存分析器,发现内存中有大量的ToolTip实例。是否值得发布一个这些实例图表/地图的图像,以查看它在哪里保持句柄? - Pure.Krome
@Pure.Krome: 可能值得考虑不再动态创建太多的工具提示,而是重复使用一个实例。 - Dmitry
很酷 :) .. 但我不知道怎么做。我希望能“重用”现有的代码……并进行“更新”。 - Pure.Krome
看这个示例,他们为按钮和复选框使用相同的工具提示实例:http://msdn.microsoft.com/en-us/library/system.windows.forms.tooltip.aspx - Dmitry

1
如果您可以在调试模式下运行应用程序,当遇到StackOverflowException并且应用程序中断进入Visual Studio时,请打开调用堆栈窗口(调试-> Windows-> 调用堆栈),查看是什么导致您的代码抛出异常。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接