問題描述
我有一個 Visual Studio 2005 C++ 程序,它在發布模式下的運行方式與在調試模式下的運行方式不同.在發布模式下,會發生(明顯的)間歇性崩潰.在調試模式下,它不會崩潰.發布版本與調試版本的工作方式不同的原因有哪些?
I have a Visual Studio 2005 C++ program that runs differently in Release mode than it does in Debug mode. In release mode, there's an (apparent) intermittent crash occurring. In debug mode, it doesn't crash. What are some reasons that a Release build would work differently than a Debug build?
還值得一提的是,我的程序相當復雜,并使用了多個 3rd 方庫進行 XML 處理、消息代理等...
It's also worth mentioning my program is fairly complex and uses several 3rd party libraries for XML processing, message brokering, etc...
提前致謝!
推薦答案
在發布版本中幸存 提供了一個很好的概述.
Surviving the Release Version gives a good overview.
我遇到的事情 - 大多數已經提到
Things I have encountered - most are already mentioned
變量初始化迄今為止最常見的.在 Visual Studio 中,調試版本顯式地將分配的內存初始化為給定值,參見例如內存值在這里.這些值通常很容易被發現,當用作索引時會導致越界錯誤,或者當用作指針時會導致訪問沖突.然而,未初始化的布爾值是真的,并且可能會導致未初始化的內存錯誤多年未被發現.
Variable initialization by far the most common. In Visual Studio, debug builds explicitly initialize allocated memory to given values, see e.g. Memory Values here. These values are usually easy to spot, cause an out of bounds error when used as an index or an access violation when used as a pointer. An uninitialized boolean is true, however, and may cause uninitialized memory bugs going undetected for years.
在內存未明確初始化的 Release 版本中,它只保留之前的內容.這導致了有趣的價值觀".和隨機"崩潰,但與確定性崩潰一樣,需要在實際崩潰的命令之前執行明顯不相關的命令.這是由第一個命令設置"引起的.具有特定值的內存位置,當內存位置被回收時,第二個命令將它們視為初始化.未初始化的堆棧變量比堆更常見,但后者也發生在我身上.
In Release builds where memory isn't explicitely initialized it just keeps the contents that it had before. This leads to "funny values" and "random" crashes, but as often to deterministic crashes that require an apparently unrelated command to be executed before the command that actually crashes. This is caused by the first command "setting up" the memory location with specific values, and when the memory locations are recycled the second command sees them as initializations. That's more common with uninitialized stack variables than heap, but the latter has happened to me, too.
無論您是從 Visual Studio(附加調試器)還是從資源管理器開始,發布版本中的原始內存初始化也可能不同.這使得最好的"一種從未出現在調試器下的發布版本錯誤.
Raw memory initialization can also be different in a release build whether you start from visual studio (debugger attached) vs. starting from explorer. That makes the "nicest" kind of release build bugs that never appear under the debugger.
有效優化在我的經驗中排在第二位.C++ 標準允許進行大量優化,這些優化可能令人驚訝但完全有效,例如當兩個指針別名相同的內存位置時,不考慮初始化的順序,或者多個線程修改相同的內存位置,并且您期望線程 B 看到線程 A 所做更改的特定順序. 通常,編譯器被指責這些.沒那么快,年輕的野地!- 見下文
Valid Optimizations come second in my exeprience. The C++ standard allows lots of optimizations to take place which may be surprising but are entirely valid e.g. when two pointers alias the same memory location, order of initialization is not considered, or multiple threads modify the same memory locations, and you expect a certain order in which thread B sees the changes made by thread A. Often, the compiler is blamed for these. Not so fast, young yedi! - see below
時間 發布構建不僅運行得更快",出于多種原因(優化、提供線程同步點的日志功能、未執行斷言等調試代碼等)操作之間的相對時間發生了巨大變化.最常見的問題是競爭條件,但也有死鎖和簡單的不同順序".執行基于消息/定時器/事件的代碼.盡管它們是時間問題,但它們可以在不同版本和平臺上出奇地穩定,復制始終有效,但在 PC 23 上除外".
Timing Release builds don't just "run faster", for a variety of reasons (optimizations, logging functions providing a thread sync point, debug code like asserts not executed etc.) also the relative timing between operations change dramatically. Most common problem uncovered by that is race conditions, but also deadlocks and simple "different order" execution of message/timer/event-based code. Even though they are timing problems, they can be surprisingly stable across builds and platforms, with reproductions that "work always, except on PC 23".
保護字節.調試構建通常在選定的實例和分配周圍放置(更多)保護字節,以防止索引溢出和有時下溢.在代碼依賴偏移量或大小的極少數情況下,例如序列化原始結構,它們是不同的.
Guard Bytes. Debug builds often put (more) guard bytes around selected instances and allocations, to protect against index overflows and sometimes underflows. In the rare cases where the code relies on offsets or sizes, e.g. serializing raw structures, they are different.
其他代碼差異 一些指令 - 例如斷言 - 在發布版本中評估為零.有時它們有不同的副作用.這在宏技巧中很普遍,就像在經典中一樣(警告:多個錯誤)
Other code differences Some instructions - e.g asserts - evaluate to nothing in release builds. Sometimes they have different side effects. This is prevalent with macro trickery, as in the classic (warning: multiple errors)
#ifdef DEBUG
#define Log(x) cout << #x << x << "
";
#else
#define Log(x)
#endif
if (foo)
Log(x)
if (bar)
Run();
在發布版本中,評估結果為 if (foo && bar)這種類型的錯誤在正常的 C/C++ 代碼和正確編寫的宏中非常罕見.
Which, in a release build, evaluates to if (foo && bar) This type of error is very very rare with normal C/C++ code, and macros that are correctly written.
編譯器錯誤 這真的從來沒有發生過.嗯 - 確實如此,但在你職業生涯的大部分時間里,假設它不存在會更好.在使用 VC6 的十年中,我發現一個我仍然確信這是一個未修復的編譯器錯誤,與對圣經(也就是標準)理解不足的數十種模式(甚至數百個實例)相比.
Compiler Bugs This really never ever happens. Well - it does, but you are for the most part of your career better off assuming it does not. In a decade of working with VC6, I found one where I am still convinced this is an unfixed compiler bug, compared to dozens of patterns (maybe even hundreds of instances) with insufficient understanding of the scripture (a.k.a. the standard).
這篇關于發布版本與調試版本的運行方式不同的一些原因是什么的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!