[英]Release mode Vs DEbug mode in MS Visual Studio Windows
我正在使用MSVS 9(VS 2008)。 我的應用程序以及共享庫(dll)(我用來鏈接我的應用程序)也是c ++環境。 現在觀察以下情況:
在調試模式下構建共享庫/ dll時,我的應用程序也在調試模式下構建結果:應用程序已成功執行
在發布模式下構建共享庫/ dll時,我的應用程序也在發布模式下構建結果:應用程序已成功執行
當共享庫/ dll在發布模式下構建並且我的應用程序也在調試模式下構建時結果:應用程序崩潰而不從調用堆棧加載任何符號。
調用堆棧:
ntdll.dll中!76e94684()
[下面的框架可能不正確和/或缺失,沒有為ntdll.dll加載符號]
ntdll.dll中!76e7d55f()
ntdll.dll中!76e5fa18()
ntdll.dll中!76e2b3c8()
當我嘗試在我的應用程序中使用以下SetName()和GetName()定義時,會出現此問題。
using namespace std;
void main()
{
Schema * schemaExp = new Schema();
schemaExp -> SetName("ExpSchema");
string srctable;
srctable=schemaExp->GetName();
cout <<"\nConnection EXPORT using the target table:" << srctable.c_str() << endl;
delete schemaExp;
}
架構類定義:
using namespace std;
class Schema
{
public:
TELAPI_EXPORT void SetName(char *name);
TELAPI_EXPORT string GetName();
protected:
string tableName;
};
void Schema::SetName(char *name)
{
string str(name);
tableName = str;
}
string Schema::GetName()
{
return tableName;
}
注意:上面的一個只是我的應用程序的一部分,我的應用程序只在#3中崩潰,並且在上面的#1和#2情況下正常工作
請幫我解決這個問題。 非常感謝任何形式的幫助。
提前致謝。
當共享庫/ dll在發布模式下構建並且我的應用程序也在調試模式下構建時結果:應用程序崩潰而不從調用堆棧加載任何符號。
那是因為這不是受支持的配置。 默認情況下,調試和發布目標鏈接到CRT的不同版本,其中(除其他外)使用不同的策略來分配內存並且彼此不兼容。
這只是更一般規則的擴展,您不應該混合鏈接到不同版本的CRT的庫。 所有項目都需要匹配。 正如你已經看到的,當他們這樣做時,一切正常。
有這方面的解決方法,但他們需要做很多工作才能做對。 實質上,您確保在單個DLL中隔離所有內存分配,以便不會跨越模塊邊界。 您需要從DLL中導出特定的函數來分配和釋放內存,以確保分配內存的堆管理器與銷毀內存的堆管理器相同。 使用new
和delete
運算符時,不能依賴於這種情況。 坦率地說,在這種情況下,我看不出所有這些努力如何為你帶來任何有用的東西。
請注意,這與是否啟用了優化無關(默認情況下,它們是發布版本,並且不在調試版本中)。 該設置與鏈接的CRT版本正交。恰好“Debug”和“Release”目標意味着多個選項。 您可以打開一個項目的優化並將其關閉另一個項目,這應該有效,只要您確保它們都鏈接到相同版本的CRT。 但同樣,我真的沒有看到這樣做的重點...如果你想為一個啟用優化,為什么你希望它們被另一個抑制?
這不應該是崩潰,但是,通常你會在Windows內存管理器中得到一個調試中斷,以警告你程序正在破壞堆。 Windows中調試堆的一個功能,可在Vista及更高版本上使用。 在“輸出”窗口中查找消息。
啟用符號服務器也很重要,這樣堆棧跟蹤就變得可讀和准確。 使用工具+選項,調試,符號並勾選預定義的msdl.microsoft.com服務器名稱前面的復選框。 為符號存儲選擇一個好的臨時目錄。 當您再次啟動程序時,它將在開始運行之前暫停一段時間,下載符號文件。 這只發生過一次。 您現在應該獲得高度可讀的堆棧跟蹤,現在也可以返回到main()方法。
您通常發現的是,跨模塊邊界公開C ++類是一件棘手的事情。 不止一件事可能出錯,這里的一種失敗模式是Schema類對象在DLL邊界兩側的大小不同。 這是因為Debug構建設置, _HAS_ITERATOR_DEBUGGING #define很重要。 它在Debug版本中默認打開,在Release版本中關閉。 很好的調試功能,但他們實現它的唯一方法是向標准C ++庫類添加字段。 這使得std :: string在Debug版本中更大。 這使您的Scheme類更大。 您現在正在避開此問題,失敗模式是具有EXE版本的DLL的調試版本。 然后,Scheme類構造函數在初始化字符串時會破壞堆,因為對象的分配不夠大。
另一種失敗模式是您的流程中有兩個版本的CRT,應用程序中的調試版本以及DLL中的發行版本。 他們不會使用相同的堆來分配。 當你在一個中分配並在另一個中釋放時會出錯。 GetName()方法返回的字符串會遇到該問題,它是在DLL內部的GetName()方法中創建的,並且在EXE中調用方法后將被銷毀。 由錯誤的分配器。 在您再次對堆執行某些操作(例如刪除Scheme對象)之前,不會檢測到導致這種堆的損壞。 如果不使用/ MD構建代碼,也可以調用此故障模式。 在VS2012 btw中解決了這個問題,所有分配現在都來自默認進程堆。
使用一致的構建設置對於在模塊邊界中生存至關重要。 設置VS解決方案以便始終始終如一地使用DLL的正確構建不是問題,只需確保DLL項目與EXE項目在同一解決方案中。
但請注意,將來你可能會遇到麻煩,DLL有自己的生活訣竅,並且可能有一天會被另一個版本的編譯器構建的應用程序使用。 Kaboom然后。 設計你的DLL接口以便永遠不會發生這種情況,但你必須放棄暴露C ++對象。 C風格的界面是后備,COM將其提升為對象模型的方式也是一種很好的方法。 當然,這非常嚴苛,如果你不能保證EXE和DLL總是同時構建和部署,那么只考慮這個。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.