簡體   English   中英

卸載DLL后,是否可以存儲在DLL中創建的對象?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM