如何调试仅在发布版本中发生的崩溃[关闭]
Posted
技术标签:
【中文标题】如何调试仅在发布版本中发生的崩溃[关闭]【英文标题】:How to debug crashes that occur in release builds only [closed] 【发布时间】:2013-08-28 08:57:22 【问题描述】:我的一个程序中有一个奇怪的竞争条件,导致它仅在发布模式和 OUTSIDE Visual Studio 环境中崩溃。
如果我在 Visual Studio 中使用 F5(发布或调试)以发布模式启动此过程,它就可以正常工作。
如果我创建带有调试信息的发布副本,它不会崩溃。
我想知道如何调试这样的问题.. 为什么它没有在 Visual Studio 中崩溃?即使在启动它的发布版本时,Visual Studio 是否会减慢可执行文件的速度?
【问题讨论】:
听起来好像在某些时候,您正在调用未定义的行为 如果它只发生在发布中,那么听起来你没有初始化所有变量。大多数编译器将在调试模式下对所有未初始化的变量进行零初始化,但在发布模式下不做任何事情(基本上使它们随机化)。提高编译器的警告级别并修复所有警告(尤其是那些与未初始化变量有关的警告)。 当你说“竞态条件”时,你究竟看到了什么让你怀疑竞态条件? 您应该尝试看看您是否可以对您的代码进行一些静态分析。这应该告诉你所有关于未初始化变量和其他内存问题的信息。 我不明白为什么这被认为过于宽泛。 “我想知道如何调试这样的问题”似乎是一个完全有效的问题。 【参考方案1】:问题实际上是如何在不改变导致崩溃的运行时行为的情况下调试应用程序。答案是更好的验尸诊断
您可以改进您的异常处理代码,如果这是一个生产应用程序,您应该这样做。
使用std::set_terminate
安装自定义终止处理程序
如果你想在本地调试这个问题,你可以在终止处理程序中运行一个无限循环,并将一些文本输出到控制台,以通知你 std::terminate
已被调用。然后附加调试器并检查调用堆栈。
在生产应用程序中,您可能希望将错误报告发送回家里,最好是连同允许您分析问题的小型内存转储一起发送。
Microsoft 具有结构化异常处理机制,可让您捕获硬件和软件异常。 See MSDN。您可以使用 SEH 保护您的部分代码,并使用与 1) 中相同的方法来调试问题。 SEH 提供了有关您在从生产应用发送错误报告时可以使用的异常的更多信息。
如果确实是竞争条件,那么正确的时机至关重要,我猜,即使在发布模式下附加调试器也会改变行为,从而改变时机
【讨论】:
【参考方案2】:这回答了“有什么不同”,但可能不是您的代码为何在发布模式下存在竞争条件的完整答案。
当您移到 VS 之外发布时,运行时正在使用哪个堆会发生变化。据我了解,即使在发布模式下,它也会在 VS 中使用调试堆。
由于根据定义必须锁定堆分配,因此使用调试堆(在将内存分配给客户端代码之前填充内存,并在释放内存时再次填充)将更频繁地阻塞竞争线程(导致更多的顺序执行),因此您可能会发现这是比赛发生的部分原因。
如果您在调试环境中设置环境变量_NO_DEBUG_HEAP=1
,(配置->调试->环境变量...),那么您将在调试器中得到相同的结果。
不幸的是,这类事情很难调试。我发现有用的一件事是存储“我去过的地方”的值数组(数组越简单越好 - 所以整数值或小字符串或其他东西),而不是每次都打印一些东西.如果您可以在调试器中停止或以某种方式检测到崩溃,则可以转储“跟踪”,并查看您如何到达现在的位置,以及涉及哪些线程。
【讨论】:
【参考方案3】:Visual Studio 中的 F5 与单独运行程序的主要区别在于,当程序最初在调试器下运行时,Windows 在特殊的调试堆上运行程序。调试堆与普通堆不同,在某些情况下,这可能导致错误仅在普通堆上表现出来。
您可以运行该程序,然后附加调试器,然后它将使用普通堆,您的错误应该很高兴地重现。为了防止程序在附加调试器之前“走得太远”,您可以在入口点内插入对 Sleep()
函数的调用。
【讨论】:
以上是关于如何调试仅在发布版本中发生的崩溃[关闭]的主要内容,如果未能解决你的问题,请参考以下文章
如何调试 iPhone 应用程序崩溃日志。仅在 App Store 购买的版本中崩溃,而不是在开发中
当系统清除内存并关闭 UIViewController 时,iOS 崩溃
为啥flutter release apk会崩溃? [关闭]