如何调试仅在发布版本中出现的崩溃

3

我的程序在某个奇怪的竞态条件下崩溃,但只在发布模式和Visual Studio外部环境下发生。

如果我使用F5在Visual Studio中以发布或调试模式启动此进程,则正常工作。

如果我创建带有调试信息的发布版本,则不会崩溃。

我想知道如何调试这样的问题...为什么在Visual Studio内部没有崩溃?即使使用发布版本,Visual Studio是否会减慢可执行文件的运行速度?


3
听起来你在某个时候触发了未定义行为。 - nikolas
2
如果这只在发布版本中发生,那么听起来你没有初始化所有的变量。大多数编译器会在调试模式下将所有未初始化的变量清零,但在发布模式下不做任何操作(基本上使它们随机)。增加编译器的警告级别并修复所有警告(特别是与未初始化变量有关的警告)。 - Martin York
4
当你说“竞态条件”时,你到底看到了什么让你怀疑出现了竞态条件? - doctorlove
1
你应该尝试并查看是否可以通过静态分析来检测你的代码。这将告诉你有关未初始化变量和其他内存问题的所有信息。 - juanchopanza
3
我不明白为什么这被认为是“过于宽泛”的。“我想知道如何调试这样的问题”似乎是一个完全合理的问题。 - Sebastian
显示剩余7条评论
3个回答

2
问题实际上是如何在不改变导致崩溃的运行时行为的情况下调试应用程序。答案是更好的事后诊断。
您可以改进异常处理代码,如果这是一个生产应用程序,则应该这样做。
  1. 使用std::set_terminate安装自定义终止处理程序。

    如果您想在本地调试此问题,可以在终止处理程序内运行一个无限循环,并将一些文本输出到控制台以通知您已调用std::terminate。然后附加调试器并检查调用堆栈。

    在生产应用程序中,您可能希望发送错误报告回家,最好附带允许您分析问题的小型内存转储。

  2. Microsoft拥有结构化异常处理机制,允许您捕获硬件和软件异常。请参阅MSDN。您可以使用SEH保护代码的某些部分,并使用与1)相同的方法来调试问题。 SEH提供了有关发生的异常的更多信息,您可以在从生产应用程序发送错误报告时使用。

如果确实是竞争条件,则正确的时间非常重要,我想,即使在发布模式下附加调试器也会改变行为,从而改变时间


1
这回答了“有什么不同”,但可能并不是为什么您的代码在发布模式下存在竞争条件的完整答案。
当您在VS之外转移到发布模式时,运行时使用的堆会发生变化。据我所知,即使在发布模式下,它在VS内部使用调试堆。
由于堆分配必须被锁定,使用调试堆(在将内存提供给客户端代码之前填充内存,并在释放内存时再次填充)会更频繁地阻止竞争线程(导致更多的顺序执行),因此您可能会发现这是竞争发生的原因之一。
如果您在调试环境中设置环境变量_NO_DEBUG_HEAP=1(配置->调试->环境变量...),则在调试器中也会得到相同的结果。

很不幸,这些问题往往很难调试。我发现有用的一件事是存储“我去过哪里”的值数组(数组越简单越好 - 所以整数值,或小字符串,或其他什么),而不是每次都打印一些东西。如果您可以在调试器中停止或以某种方式检测到崩溃,则可以转储“跟踪”,并查看如何到达当前位置以及涉及哪些线程。


1
Visual Studio中按F5与单独运行程序的主要区别在于,当程序在调试器下初始运行时,Windows会在特殊的Debug堆上运行程序。Debug堆与普通堆不同,在某些情况下,这可能导致错误只在普通堆上表现出来。您可以先运行程序,然后再附加调试器,这样它就会使用普通堆,并且您的错误应该能够愉快地复现。为了防止程序在您附加调试器之前“走得太远”,您可以在入口点中插入对Sleep()函数的调用。

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