我有一个Windows Forms应用程序,它使用SQLite文件作为文件格式。这些文件由本机代码创建,该代码通过C ++ / CLI包装器调用,其中包括对托管代码的回调以进行进度/取消更新。这对于32位一直很有用。我试图通过切换到64位来消除我的内存上限,并遇到了一个重大障碍。
当在本机代码中分配或释放内存时,我得到伪确定性崩溃,这让我想到了内存损坏。但它只发生在发布版本中,并且只是没有附加调试器。这是我噩梦的细分:
Config Bits Optimizations Interop Dbg-symbols Runtime With-debugger Without-debugger Release 32 on no no /MD no crash no crash Release 64 on yes no /MD no crash no crash Release 32 on yes no /MD no crash no crash Release 64 on yes no /MD no crash crash Release 64 on yes yes /MD no crash crash Release 64 off yes no /MD no crash no crash Release 64 off yes yes /MD no crash no crash Debug 32 off no yes /MDd no crash no crash Debug 32 off yes yes /MDd no crash no crash Debug 64 off yes yes /MDd no crash no crash Debug 64 on yes yes /MD no crash no crash Debug 64 on yes no /MD no crash no crash Debug 64 off yes yes /MD no crash no crash Debug 64 off yes yes /MDd no crash no crash Debug 64 on yes yes /MDd no crash no crash Debug 64 on yes no /MD no crash no crash
“Interop”意味着我正在使用GUI应用程序中的C ++ / CLI包装器来运行本机解析器代码。我有一个用本机C ++编写的命令行驱动程序,它不会在任何配置中崩溃。
基本上调试配置永远不会崩溃,即使本机代码编译完全像发布代码!我比较了响应文件,它们是相同的,除了我为调试配置添加了_NO_DEBUG_HEAP = 1。我怀疑在使用/ MD和定义NDEBUG时无论如何都会产生任何影响。那我该怎么调试这个噩梦?它不觉得我的代码有问题。请不要问一个小的复制品,我不知道如何制作它。但是代码都是开源的,所以如果有人想要重现这个,我会发布一个链接到源代码。
答案 0 :(得分:0)
Heisenbugs通常由内存踩踏(在托管代码中不会发生)或将内存中的垃圾视为有效数据引起。
我已经找到了多个通常可重复的heisenbugs,这些heisenbugs使用了一个未初始化的变量,可以从另一个例程中拾取堆栈中的任何内容。您的本机代码可能包含这样的错误,当它获得一个值时会起作用,而当它获得另一个值时会爆炸。调试与发布不保证幕后的东西是一样的(毕竟,如果这就是为什么会有这两种配置?)并且你可能在内存中有不同的垃圾。
优化器也可能有这样的效果。
我会尝试一件事:将一个实质性结构压缩到本机代码中第一个例程的局部变量中。做一些事情来防止链接器剥离它。
这会移动一些东西,如果它是内存中的垃圾问题,这应该会改变行为。