仅在发布编译模式下出现但在调试模式下不会出现的错误和异常程序行为的典型原因是什么?

有帮助吗?

解决方案

很多时候,在调试模式下在C ++中的所有变量都初始化为空,而除非明确说明同样不在释放模式发生。

检查任何调试宏和未初始化的变量

请问你的程序使用线程,则优化也可能会导致在释放模式的一些问题。

此外,检查所有的异常,例如没有直接关系的释放方式,但有时我们只是忽略了一些重要的例外,如MEM访问冲突在VC ++,但同样可以在其他操作系统如Linux,Solaris至少到成为一个问题。理想的情况是你的程序不应该赶上像访问一个空指针这样重要的例外。

其他提示

一个常见的问题是使用具有ASSERT内副作用的表达式。

其他差异可能是:

  • 在收集垃圾的语言中,收藏家通常在发布模式下更具侵略性。
  • 记忆的布局通常可能不同。
  • 内存可以不同初始化(例如,在调试模式下可以归零,也可以更积极地使用释放);
  • 当地人可以晋升为发行中的寄存器值,这可能会导致浮点值的问题。

过去我遇到过许多错误,这些错误在调试版本中表现良好,但在发布版本中崩溃。有许多根本原因(当然包括那些已经在本线程中总结的原因),并且我被以下所有原因所困扰:

  • 成员变量或成员函数 #ifdef _DEBUG, ,以便类在调试版本中具有不同的大小。有时 #ifndef NDEBUG 用于发布版本
  • 同样,还有一个不同的 #ifdef 它恰好只存在于两个版本之一中
  • 调试版本使用系统库的调试版本,特别是堆和内存分配函数
  • 发布版本中的内联函数
  • 头文件的包含顺序。这不应该引起问题,但是如果你有类似的东西 #pragma pack 尚未重置,那么这可能会导致严重的问题。使用预编译头和强制包含也会出现类似的问题
  • 缓存:您可能有一些代码,例如仅在发布版本中使用的缓存,或者不同的缓存大小限制
  • 项目配置:调试和发布配置可能有不同的构建设置(使用 IDE 时很可能会发生这种情况)
  • 由于仅调试代码而发生的竞争条件、时序问题和各种副作用

我多年来为深入了解调试/发布错误而积累的一些技巧:

  • 如果可以的话,尝试在调试版本中重现异常行为,甚至更好的是编写单元测试来捕获它
  • 想想两者之间有什么不同:编译器设置、缓存、仅调试代码。尝试暂时最小化这些差异
  • 创建关闭优化的发布版本(这样您更有可能在调试器中获得有用的数据),或优化的调试版本。通过最小化调试和发布之间的更改,您更有可能能够隔离导致错误的差异。

是的!如果有条件编译,可能存在错误的定时(优化的释放码诗,非优化的调试代码),存储器重新使用与调试堆。

它可以,特别是如果你在C境界。

一个原因可能是因为调试版本可能会添加代码来检查野指针并以某种方式保护您的代码崩溃(或出现错误的行为)。如果是这样的话,你应该仔细检查你从你的编译器警告,获得和其他信息。

另一个原因可能是优化(这通常是针对发布版本和关闭调试)。代码和数据的布局可能已经进行了优化,而您的调试程序公正是,例如,访问未使用的内存,发行版本目前正试图访问保留内存,甚至指向代码!

编辑:我看其他提到:当然,你可能有,如果在调试模式下不会在编译有条件排除整个代码段。如果是这样的话,我希望是真的调试代码,这也不是程序本身的正确性至关重要!

在CRT库函数在调试VS释放行为不同(/ MD VS / MDD)。

例如,在调试版本常常充液传递给所指示的长度的缓冲区验证要求。例子包括strcpy_sStringCchCopy,等等。即使琴弦较早终止,您的 szDest 的最好是名词的字节长!

当然,例如,如果使用结构等

#if DEBUG

//some code

#endif

在.NET中,即使你不使用条件编译像#if DEBUG,编译器仍然是很多更自由的在释放模式的优化比它在调试模式下,这可能会导致仅释放错误也是如此。

您就需要给予更多的信息,但是,是的,这是可能的。这取决于你的调试版本做什么。您可能也有记录或在额外的检查不被编译成一个发布版本。这些只调试代码路径可能会产生意想不到的副作用,改变状态或影响以奇怪的方式变量。调试版本通常运行速度较慢,因此这可能会影响线程和隐藏的竞争条件。同样为从释放编译直线前进的优化,这是可能的(虽然不太可能这些天),一个释放编译可能会短路的东西作为优化。

如果没有更多的细节,我会认为“不正常”的意思,它要么不编译或抛出在运行时某种错误。检查您是否有依赖于编译版本,可通过#if DEBUG陈述或者通过标有Conditional属性方法的代码。

这是可能的,如果你有条件编译使调试代码和发布代码是不同的,因此存在仅在释放模式下使用的代码中的错误。

除此之外,这是不可能的。还有如何调试代码和发布代码被编译的差异,并在如果调试器下运行与否是如何执行的代码差异,但如果有这些差异造成比的性能差异等什么,问题在那里一直。

在调试版本错误可能不存在的(因为定时或存储器分配是不同的),但是,这并不意味着该错误是不存在。也有可能是不相关的改变代码的时间,导致发生错误或不调试模式等因素的影响,但是这一切都归结为一个事实,即如果代码是正确的,就不会出现错误在任何的情况。

所以,不,调试版本也不行,因为你可以在没有得到一个错误运行。如果当你在释放模式运行过程中出现错误,这是不是因为释放模式,这是因为错误从一开始就在那里。

有那个的编译器优化能打破有效的代码的,因为他们太咄咄逼人了。

试着用开启不太优化的编译代码。

在一个非void函数,所有的执行路径应与return语句结束。

在调试模式下,如果忘记结束与一个返回语句这样的路径,则函数通常默认返回0。

然而,在释放模式的函数可能返回无用值,这可能会影响你的程序运行。

这是可能的。如果碰巧没有条件编译参与,比你可以确信你的程序是错误的,并正在努力在调试模式,因为偶然的内存初始化的唯一或内存甚至布局!

我刚经历的是,当我打电话未恢复寄存器的先前的值的组件的功能。

在“释放”的配置,VS用/ O2这优化了代码速度进行编译。因此,一些局部变量仅其中映射到将其用上述的功能,导致严重的存储器讹误共享CPU寄存器(优化)。

总之看到,如果你没有间接地与CPU寄存器在你的代码搞乱任何地方。

我记得不久前我们用c/c++构建dll和pdb。

我记得这个:

  • 添加日志数据有时会使错误移动或消失,或者出现完全其他错误(因此这实际上不是一个选项)。
  • 其中许多错误是由于 strcpy 和 strcat 中的字符分配以及 char[] 数组等造成的......
  • 我们通过运行边界检查器并简单地修复内存Alloc/DealLoc问题来淘汰一些问题。
  • 很多时候,我们系统地检查代码并修复字符分配(就像检查所有文件一样)。
  • 肯定与内存分配和管理以及调试模式和释放模式之间的约束和差异有关。

然后抱有最好的希望。

有时,我会在处理这些错误时临时向客户提供 dll 的调试版本,以免耽误生产。

另一个原因可能是DB的呼叫。 你是否保存和更新在同一个线程相同的记录多次, 有时更新。 其可能的更新失败或没有工作如预期,因为以前创建命令仍在处理和更新,数据库调用失败找到任何记录。 这在调试不会发生的调试器可以确保在着陆之前完成所有尚未完成的任务。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top