使用 Visual Studio 调试器与不使用调试器运行可执行文件之间的差异
我正在尝试调试一个问题,即当直接从 Visual Studio 执行时,可执行文件会产生可重复的输出(这是我想要的),但从命令提示符执行时不会产生可重复的输出.这是一个单线程应用程序,所以在时间方面不应该有任何奇怪的行为.
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.
有人能列举出两种环境之间可能存在的差异吗?
Can somebody enumerate what possible differences could be between the two environments?
我确信实际的可执行文件是相同的――它们都是发布版本并且运行相同的 .exe 文件.
I'm sure the actual executable is the same -- they're both release builds and are running the same .exe file.
以下是环境和结果:
- 直接从命令提示符 (cmd) 运行:不可重复输出
- 通过调试 (F5) 从 Visual Studio 运行:可重复输出
- 在不调试的情况下从 Visual Studio 运行 (Ctrl-F5):不可重复的输出
我知道工作目录可能不同,但我正在手动调整它以确保工作目录相同.
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.
基于这些结果,看起来运行带调试"(即使在发布版本中)以某种方式解决了问题.这是否指向一个可能的罪魁祸首?运行带有调试和不带调试的可执行文件有什么区别?
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?
解决方案:正如已接受的答案中所指出的,调试堆是问题所在.问题是在我们代码的深处,有人在初始化之前访问了大型数组的一部分.他们用 malloc 分配了内存,并且没有将内存初始化为 0.调试堆会(我假设)用一些可重复的值填充数组,而当调试器没有连接时(即从命令行运行或使用Ctrl-F5)这些值更随机,有时会导致程序行为的微小偏差.不幸的是,调整是如此微妙以至于几乎无法察觉,并且在处理的第一个帧"之后,有问题的内存被正确重置,但初始条件已经略有不同,损坏已经完毕.混沌理论在行动!感谢您的指导.
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.
一个很有帮助的调试技巧:编写一个自定义 malloc,立即用完全随机的数据填充内存.这样,您可以确保在使用它之前自己正确地初始化它,否则每次运行它时您的结果都会(希望如此)疯狂――即使在调试模式下使用调试堆!
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!
推荐答案
如果进程在调试器下启动,Windows 堆的行为会有所不同. 要禁用此行为(以便在调试时发现问题)将 _NO_DEBUG_HEAP=1 添加到环境中(如 这个问题).
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).
或者,您可以在程序执行的早期附加到进程.堆将不会进入调试模式.在执行开始的某处添加 DebugBreak()
行,使用 Ctrl+F5 运行,并在要求时开始调试.
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.
相关文章