我有一个Visual Studio 2005 C++程序,它在Release模式下的运行方式与在Debug模式下的运行方式不同.在发布模式下,发生(明显的)间歇性崩溃.在调试模式下,它不会崩溃.Release构建与Debug构建不同的原因是什么?
值得一提的是,我的程序相当复杂,并使用多个第三方库进行XML处理,消息代理等...
提前致谢!
幸存版本 提供了很好的概述.
我遇到的事情 - 大多数已经提到过
变量初始化 是目前最常见的.在Visual Studio中,调试版本明确地将已分配的内存初始化为给定值,请参阅此处的内存值.这些值通常很容易被发现,当用作索引时会导致越界错误,或者当用作指针时会导致访问冲突.但是,未初始化的布尔值是正确的,并且可能导致未初始化的内存错误多年未被检测到.
在发布版本中,内存未被明确初始化,它只保留以前的内容.这会导致"有趣的值"和"随机"崩溃,但往往是确定性的崩溃,需要在实际崩溃的命令之前执行明显不相关的命令.这是由第一个命令"设置"具有特定值的内存位置引起的,当内存位置被回收时,第二个命令将它们视为初始化.对于未初始化的堆栈变量而言,这比堆更常见,但后者也发生在我身上.
无论是从visual studio(附加调试器)还是从explorer开始,原始内存初始化在发布版本中也可能不同.这使得"最好"的版本构建错误从未出现在调试器下面.
有效的优化在我的exeprience中排名第二.C++标准允许进行大量的优化,这可能是令人惊讶的,但是完全有效,例如当两个指针别名相同的内存位置,初始化顺序不被考虑,或者多个线程修改相同的内存位置,并且您期望某个顺序其中线程B看到线程A所做的更改.通常,编译器会因此而受到指责.没那么快,年轻的yedi!- 见下文
由于各种原因(优化,提供线程同步点的日志记录功能,未执行的断言等调试代码等),时序发布版本不仅"运行得更快",而且操作之间的相对时序也发生了显着变化.最常见的问题是竞争条件,但也有死锁和简单的"不同顺序"执行消息/定时器/基于事件的代码.即使它们是计时问题,它们在构建和平台上也可以令人惊讶地保持稳定,复制"始终有效,除了在PC 23上".
守卫字节.调试版本通常在所选实例和分配周围放置(更多)保护字节,以防止索引溢出和有时下溢.在极少数情况下,代码依赖于偏移量或大小,例如序列化原始结构,它们是不同的.
其他代码差异某些指令 - 例如断言 - 在发布版本中评估为空.有时他们有不同的副作用.这在宏观技巧中很普遍,如经典(警告:多个错误)
#ifdef DEBUG #define Log(x) cout << #x << x << "\n"; #else #define Log(x) #endif if (foo) Log(x) if (bar) Run();
在发布版本中,评估为if(foo && bar) 这种类型的错误在普通C/C++代码和正确编写的宏中非常罕见.
编译器错误这真的永远不会发生.嗯 - 确实如此,但是如果不这样做,那么你在职业生涯的大部分时间里会更好.在与VC6合作的十年中,我找到了一个我仍然相信这是一个未修复的编译器错误,与几十个模式(甚至数百个实例)相比,对经文(也就是标准)的理解不足.
在调试版本中,通常启用断言和/或调试符号.这可能导致不同的内存布局.如果指针错误,数组溢出或类似的内存访问,则在一种情况下访问一个严重的坏内存(例如函数指针),在其他情况下可能只是一些非关键内存(例如,只是一个doc字符串被删除)
未明确初始化的变量将在发布版本中归零或不归零.