2012-06-13 51 views
0

我有一個使用SQLite文件作爲文件格式的Windows窗體應用程序。這些文件由通過C++/CLI包裝器調用的本地代碼創建,其中包括對託管代碼的回調以進行更新/取消更新。這對於32位工作非常有效。我試圖通過切換到64位來消除我的內存限制,並且遇到了一個主要障礙。C#項目中的「優化代碼」選項如何導致本機代碼崩潰?

當內存在本地代碼內被分配或釋放時,我得到了僞確定性崩潰,這讓我想到了內存損壞。但它只發生在發佈版本中,只有在沒有附加調試器的情況下才會發生。這是我噩夢的細分:

 
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 

「互操作」指的是我使用從GUI應用程序中的C++/CLI包裝來運行原有的語法分析器代碼。我有一個用本地C++編寫的命令行驅動程序,它不會在任何配置中崩潰。

基本上調試配置永遠不會崩潰,即使當本機代碼編譯完全像釋放代碼!我比較了響應文件,它們是相同的,除了我爲調試配置添加了_NO_DEBUG_HEAP = 1。無論如何,當我使用/ MD和定義NDEBUG時,我懷疑它有什麼影響。那麼,我該如何調試這個噩夢?它不覺得它是我的代碼的問題。請不要要求一個小的repro,我不知道如何做到這一點。但代碼全部是開源的,所以如果有人想重現這一點,我會發佈一個鏈接到源代碼。

+0

添加'Trace :: WriteLine'來隔離到特定位置的崩潰。一旦你知道位置,你會找出原因。 –

+0

@RomanR .:我怎麼可以在本機代碼中添加?我使用日誌記錄來將崩潰隔離到代碼的某些部分;這就是我知道這可能與分配或釋放內存有關。一個配置在清除矢量>時崩潰了,但實際上不應該釋放任何內存,它應該只是遞減所有ptrs的ref-count(它們全部都保存在別處)。我希望這很容易。 :( –

+0

更新:我發現可以通過關閉C#項目中的「優化代碼」來避免崩潰(這就是爲什麼具有本機優化的調試配置可以正常工作的原因)。如何才能導致本機崩潰代碼?! –

回答

0

Heisenbugs通常是由內存跺腳(託管代碼中不會發生)或通過將內存垃圾視爲有效數據引起的。

我已經找到了多個通常可重複使用的heisenbugs,這些heisenbugs使用了一個未初始化的變量,它會從另一個例程中拾取堆棧中的任何東西。你的本地代碼可能包含這樣一個錯誤,當它獲得一個值時會起作用,並在它變成另一個時發生爆炸。調試vs發佈並不能保證幕後的東西是相同的(畢竟,如果這是爲什麼會有這兩種配置?),你可能在內存中有不同的垃圾。

優化器也可能有這樣的效果。

我想嘗試的一件事:在本地代碼中將一個實質結構打包成第一個例程的局部變量。用它做點什麼來阻止鏈接器剝離它。

這會移動東西,如果它是垃圾內存問題,這應該改變行爲。

+0

爲什麼本機代碼中的這樣的錯誤不會被我的非Interop案例中的調試堆捕獲? –

+0

@MattChambers:其他版本可能會在內存中留下可接受的東西。 –