問題描述
我正在嘗試調(diào)試一個問題,即當(dāng)直接從 Visual Studio 執(zhí)行時,可執(zhí)行文件會產(chǎn)生可重復(fù)的輸出(這是我想要的),但從命令提示符執(zhí)行時不會產(chǎn)生可重復(fù)的輸出.這是一個單線程應(yīng)用程序,所以在時間方面不應(yīng)該有任何奇怪的行為.
I'm trying to debug an issue in which an executable produces repeatable output (which I want) when executed directly from Visual Studio, but does not produce repeatable output when executed from the command prompt. It's a single-threaded application, so there shouldn't be any strange behaviour there in terms of timing.
有人能列舉出兩種環(huán)境之間可能存在的差異嗎?
Can somebody enumerate what possible differences could be between the two environments?
我確信實際的可執(zhí)行文件是相同的——它們都是發(fā)布版本并且運行相同的 .exe 文件.
I'm sure the actual executable is the same -- they're both release builds and are running the same .exe file.
以下是環(huán)境和結(jié)果:
- 直接從命令提示符 (cmd) 運行:不可重復(fù)輸出
- 通過調(diào)試 (F5) 從 Visual Studio 運行:可重復(fù)輸出
- 在不調(diào)試的情況下從 Visual Studio 運行 (Ctrl-F5):不可重復(fù)的輸出
我知道工作目錄可能不同,但我正在手動調(diào)整它以確保工作目錄相同.
I know that the working directory can possibly be different, but I'm manually adjusting that to make sure that the working directory is identical.
基于這些結(jié)果,看起來運行帶調(diào)試"(即使在發(fā)布版本中)以某種方式解決了問題.這是否指向一個可能的罪魁禍?zhǔn)?運行帶有調(diào)試和不帶調(diào)試的可執(zhí)行文件有什么區(qū)別?
Based on these results, it looks like running "with Debugging" (even in a Release build) somehow fixes the problem. Does this point to a likely culprit? What are the differences between running an executable with debugging and without?
解決方案:正如已接受的答案中所指出的,調(diào)試堆是問題所在.問題是在我們代碼的深處,有人在初始化之前訪問了大型數(shù)組的一部分.他們用 malloc 分配了內(nèi)存,并且沒有將內(nèi)存初始化為 0.調(diào)試堆會(我假設(shè))用一些可重復(fù)的值填充數(shù)組,而當(dāng)調(diào)試器沒有連接時(即從命令行運行或使用Ctrl-F5)這些值更隨機,有時會導(dǎo)致程序行為的微小偏差.不幸的是,調(diào)整是如此微妙以至于幾乎無法察覺,并且在處理的第一個幀"之后,有問題的內(nèi)存被正確重置,但初始條件已經(jīng)略有不同,損壞已經(jīng)完畢.混沌理論在行動!感謝您的指導(dǎo).
SOLUTION: As pointed out in the accepted answer, the debug heap was the issue. The problem was that deep in the bowels of our code, somebody was accessing parts of a large array before they were initialized. They had allocated memory with a malloc and had not initialized the memory to 0. The debug heap would (I assume) fill the array with some repeatable value, whereas when the debugger wasn't attached (i.e. when run from the command line or with Ctrl-F5) the values were more random and would sometimes cause tiny deviations in the behaviour of the program. Unfortunately, the adjustment was so subtle as to almost be unnoticeable, and the memory in question was properly reset after the first "frame" of processing, but the initial conditions were already slightly different and the damage had been done. Chaos theory in action! Thanks for the guidance.
一個很有幫助的調(diào)試技巧:編寫一個自定義 malloc,立即用完全隨機的數(shù)據(jù)填充內(nèi)存.這樣,您可以確保在使用它之前自己正確地初始化它,否則每次運行它時您的結(jié)果都會(希望如此)瘋狂——即使在調(diào)試模式下使用調(diào)試堆!
One great debugging tip that helped out: write a custom malloc that immediately fills memory with completely random data. That way, you can make sure you're properly initializing it yourself before using it, otherwise your results will be (hopefully) crazy every time you run it -- even in debug mode with the debug heap!
推薦答案
如果進程在調(diào)試器下啟動,Windows 堆的行為會有所不同. 要禁用此行為(以便在調(diào)試時發(fā)現(xiàn)問題)將 _NO_DEBUG_HEAP=1 添加到環(huán)境中(如 這個問題).
Windows Heap behaves differently if process is started under the debugger. To disable this behavior (in order to find a problem while debugging) add _NO_DEBUG_HEAP=1 to environment (like in this question).
或者,您可以在程序執(zhí)行的早期附加到進程.堆將不會進入調(diào)試模式.在執(zhí)行開始的某處添加 DebugBreak()
行,使用 Ctrl+F5 運行,并在要求時開始調(diào)試.
Alternatively you can attach to process early in program execution. Heap will not enter the debug mode then. Add DebugBreak()
line somewhere in the beginning of the execution, run with Ctrl+F5, and start debugging when asked to.
這篇關(guān)于使用 Visual Studio 調(diào)試器與不使用調(diào)試器運行可執(zhí)行文件之間的差異的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!