【问题标题】:what to do if debug runs fine, but release crashes如果调试运行良好,但发布崩溃怎么办
【发布时间】:2011-04-30 01:49:08
【问题描述】:

我有一个在调试版本中运行良好的应用程序,但是当我在发布版本中启动它时,我得到了一个

unhandled Exception at 0x0043b134 in myapp.exe: 0xC0000005:
Access violation while reading at position 0x004bd96c

如果我点击“break”,它会告诉我没有加载任何符号并且无法显示源代码。

在这种情况下我可以做些什么来追查问题?

【问题讨论】:

  • 这有时是因为内存问题。通常发布版本在这方面不太宽容。你的程序会不会有内存泄漏、缓冲区溢出等问题?
  • 看起来您删除了某些内容,但请尝试使用它。无论如何,您实际上可以发布一些代码吗?如果你不告诉我们你在做什么,我们什么都做不了。
  • 应用程序很大——甚至不知道我可以发布哪一部分代码,因为我不知道错误发生在哪里
  • 这种情况发生在我身上,我一般都会早早去酒吧……
  • 这通常是因为调试版本会初始化你没有显式初始化的变量。当您在发布模式下构建时,这些变量现在包含一个随机值,而不是调试模式为您设置的漂亮的 0 (NULL) 值。要解决此问题,请将编译器警告设置为更高级别并修复所有警告(尤其是那些提到未初始化变量的警告)。 PS。警告通常是一个问题,因此请始终修复它们并将编译器警告级别设置为最高。

标签: c++ debugging crash release


【解决方案1】:

这类问题通常是由单元化变量引起的。我会从那里开始寻找你的问题。

调试模式更宽容,因为它通常被配置为初始化尚未显式初始化的变量。

也许您正在删除一个未初始化的指针。在调试模式下它可以工作,因为指针被清空并且 delete ptr 将在 NULL 上正常。发布时有些垃圾,然后删除 ptr 实际上会导致问题。

【讨论】:

  • 这听起来很合理!我可以告诉 Visual Studio 不要在调试版本中初始化变量吗?
  • 我在调试版本中激活了 /RTCu(非初始化变量) - 如果有任何未初始化的变量,不应该这样唠叨吗?
  • 在大多数情况下是的,但并非在所有情况下。如果指针可以通过其他方式初始化,则忽略此检查。在实践中,您可能已经使用了 & 运算符的地址并通过指针初始化了变量。所以它仍然可能缺少初始化并且没有产生警告。见msdn.microsoft.com/en-us/library/8wtf2dfz.aspx
【解决方案2】:

这可能是两件事:

  • 除了检查本身之外,您的一个或多个断言确实有必要的工作
  • 别的东西

要排除前者,请尝试在调试版本中将assert 重新定义为空操作。如果缺少某些断言导致崩溃,您会看到它。否则,就是另外一回事了。

另外,我假设你有版本控制。这才刚刚开始发生吗?您可以分析上周的代码更改。

最后,即使在调试模式下没有崩溃,运行内存检查器工具也可能有助于发现错误的内存访问。

【讨论】:

  • 我对我的所有项目都使用版本控制,除了那个,因为我正在开发的这台特定机器没有连接到互联网:/愚蠢的我......我重新定义了断言什么都不做,它在调试版本中不会崩溃。我会用谷歌搜索“内存检查工具”——你能推荐一个吗?
  • @Mat:还要考虑@Grozz 的使用日志输出的建议。这肯定会给它一些启示。
【解决方案3】:

两步:

a) 使用调试构建发布版本 符号(至少 VS 可能)

b) 构建发布构建没有 优化

如果问题仍然存在,它非常好并且易​​于修复。好像问题出在调试版本中。

如果问题发生在优化设置上,那真的很棘手,必须根据具体情况进行处理。

【讨论】:

  • 如果我使用调试符号构建版本,它不会崩溃
  • @Mat:这非常很奇怪,因为二进制文件(出于所有目的)应该是相同的。主要区别在于“调试符号”选项创建了一个单独的 .PDB 文件,描述了内存地址和函数/变量之间的关系。 IE。这应该会告诉您地址 0x0043b134 或地址 0x004bd96c 的内容。
  • @MSalters:我认为原因是发布二进制文件总是经过一些优化(例如 /O2)。我怀疑这与优化标志有关。
  • 这里的说法是“正常”发布构建崩溃,但不是带有符号的发布构建。这很奇怪,因为两个构建都应该具有相同的优化标志等。但是,我确实注意到/DEBUG 暗示/OPT:NOREF, /OPT:NOICF;该文档指出,您需要为带有调试信息的发布版本明确设置它们。这两个旗帜现在将是我的主要嫌疑人。
【解决方案4】:

main 函数的开头开始跟踪此处和此处插入日志输出的问题。

【讨论】:

    【解决方案5】:

    如果不是内存问题,那么您必须在版本中启用断言。对于内存问题,我希望你有好的单元测试。使用 valgrind 可以轻松解决此类问题。

    顺便说一句,为什么人们在发布版本中禁用断言?在 99% 的情况下,它们不会导致性能问题,并且能够很好地检测错误。

    【讨论】:

      【解决方案6】:

      在 Windows 上使用 Microsoft debugdiag 进行故障转储(它是免费的)并使用相同的方法分析转储。它为崩溃的函数提供了一个很好的调用堆栈。但是,如果它一直在到处崩溃,则可能是堆损坏的问题。然后,您需要结合 debugdiag 使用全局标志(或 gflags,它是用于调试套件的 microsoft 工具的一部分,它是免费的)。 Gflags 将为您提供堆实际损坏的位置。希望对您有所帮助。

      【讨论】:

        【解决方案7】:

        我遇到了这个问题,在 Visual Studio 中发布/调试工作正常,独立调试工作,但独立发布崩溃。调试对我来说不是特别准确,我的解决方案是:

        注释掉大部分代码,然后构建、测试、取消注释、重复,直到找到导致崩溃的部分。

        在我的例子中,它传递一个指向一个对函数来说太小的数组的指针。

        【讨论】:

          【解决方案8】:

          您确定两个版本都使用相同的 .dll 吗?我花了一个小时想知道为什么我的程序在调试模式下编译而不是在发布模式下编译,我只是忘记更新发布文件夹中的 dll。

          【讨论】:

            【解决方案9】:

            不看代码,很难判断什么是坏的。上述所有建议都很好而且很有帮助,但我发现解决这类问题最有帮助的是分块运行程序的某些部分。即,注释掉很多代码/功能,然后运行程序并查看它是否崩溃。如果没有,请取消注释某些功能,然后重新运行,依此类推。这样您就可以将问题范围缩小到导致此问题的确切代码。

            在大多数情况下,这是由于 Debug 构建可以防止的某些缓冲区溢出造成的。

            【讨论】:

              【解决方案10】:

              对我来说,问题在于构造函数以错误的顺序初始化 2 个成员变量。即与它们的声明顺序不同。
              我很惊讶初始化顺序实际上有什么不同。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2015-06-03
                • 2016-05-26
                • 1970-01-01
                • 1970-01-01
                • 2018-09-13
                • 1970-01-01
                相关资源
                最近更新 更多