[英]Can I store objects created in a DLL after unloading the DLL?
我需要對以下代碼進行一些說明。
在下面的代碼中,我從DLL中檢索接口的私有實現。
DLL卸載后(案例2),從接口檢索的字符串和接口本身都變得無效,並且在訪問它們時會發生(預期)訪問沖突。
但是令我困惑的是,當我重新加載DLL時,我可以再次使用接口和字符串,而無需從DLL中重新獲取它們。
這應該這樣工作嗎?
如何使內存變得無效,並且一旦再次加載DLL,它們突然又變得有效?
這是否很幸運,並且由於我的測試程序相對簡單,因此DLL方便地第二次加載到內存中的完全相同的位置?
int main(int argc, int *argv[])
{
Interface *itf;
const char *name;
{
// loads the dll and gets functions
PersistenInterface pi("PersistentInterface.dll");
// returns a private implementation of the interface
itf = pi.CreateInterface();
name = itf->GetName();
// CASE #1
cout << name << endl; // suceeds
} // dll is unloaded in ~PersistenInterface()
// CASE #2
//cout << name << endl; // crashes
//cout << itf->GetName() << endl; // crashes
{
PersistenInterface pi("PersistentInterface.dll");
// CASE #3
cout << name << endl; // suceeds !?
cout << itf->GetName() << endl; // suceeds !?
}
return 0;
}
我希望您不要從DLL返回堆棧上的本地對象。 函數從DLL返回后,本地對象將被破壞,因此肯定會導致系統崩潰。 它與DLL的概念無關。 如果嘗試在包含函數返回后引用本地對象,則會遇到相同的問題。
如果內存是動態分配在DLL內的堆上的,則在DLL未初始化后它仍然有效。 您仍然可以在主應用程序中使用內存,因為DLL本身不擁有任何東西。 請記住,堆屬於進程,而不是DLL。
但是,一般規則是該內存的所有者(創建該內存的所有者,例如您的情況下的DLL)負責釋放相同的內存。 如果雙方使用不同的CRT實例,則在DLL中分配內存並將其分配到另一端可能會導致不必要的麻煩。
答案有點復雜。 實際上,如果加載DLL,則它實際上並沒有加載到堆內存中。 它被加載到全局內存中,並且該內存被映射到您的地址空間。通過這種機制,操作系統可以節省內存,因為它可以將相同的代碼映射到不同的進程中。 因此,如果您訪問DLL空間內的地址,則訪問將被重定向到DLL實際存在的全局內存中。 卸載后,此地址不再有內存。 您的訪問將不再被重定向,將引發異常。 這與malloc和free(或new和delete)不同,后者僅將內存標記為未使用,但仍將其所有數據標記為未使用(除非激活了零內存)。 靜態DLL數據(如常量字符串)和DLL代碼的行為如上所述。 再次加載DLL后,具有的地址(顯然直接指向靜態數據或代碼)將再次變為有效。 至少Windows XP始終在相同的地址空間加載DLL。 但是不要依靠這個! 出於安全原因,現代OS可以決定在每次使用loadLibrary或每次啟動進程時將進程的DLL映射到不同的地址。 據我所知,在調試器中或在Windows XP中,DLL始終映射到相同的地址,這就是代碼行為的原因。 它不是錯誤或功能,而是DLL概念。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.