2014-02-19 27 views
3

TL; DR:是否可以在運行時從庫中加載類對象,關閉庫然後將對象用作「普通」對象(關閉後)?從庫中動態加載類並在關閉庫之後使用它

我試圖用某種「熱插拔」功能實現插件系統。假設我的程序期望從其插件獲取doSomething()函數。我的想法是掃描文件系統以查找特定文件夾中的任何庫,提取函數,然後關閉庫(在使用函數之前!)。這樣,監視器線程可以監視文件系統上的更改,並在發生更改時重置函數指針,從而插件可以「熱插拔」。

我相信函數指針在我關閉庫後就會失效(是這樣嗎?)。因此,我的想法是讓庫返回一個具有所需功能的對象的副本。在這種情況下,我會調用lib在關閉它之前創建該對象,並將該對象的副本保存在我的程序中。但是,由於對象可以使用庫的其他對象/函數,因此我不確定這是否可行,因爲這些對象/函數將不可用,是否它們?

+0

可能重複的[在存儲器中複製的函數並執行它(http://stackoverflow.com/questions/4546071/copy-a-function-in-memory-and-execute-it) – Vality

+0

我認爲這是有效的問他是否可以將函數的代碼複製到他自己的程序的內存中,這樣他就不必使用系統鏈接器,有效地編寫他自己的具有更多功能的鏈接器...... – Vality

+0

不是真的在我看來,但感謝鏈接!由於我不知道插件的複雜程度有多複雜,所以我不知道究竟我需要加載到內存中以及它是如何構建的。 – user1228633

回答

4
  1. 您不能複製對象並關閉庫,因爲只有數據,而不是這些對象的代碼被複制。而不是OS將庫的代碼加載到內存中,所有的函數指針都指向這個內存區域。如果操作系統卸載了庫,會怎麼樣?

  2. 你可以實現這樣的東西。您可以擁有一個包含指向當前加載的實現的指針的代理對象。如果檢測到新庫,則可以加載新庫,創建新實現的實例,刪除舊實例,關閉舊庫。通過這種方式實現「熱插拔」機制,避免共享庫代碼出現問題。

  3. 如果您選擇了第2項中描述的方式,請注意併發性問題(如果在刪除舊實現時但在指針更改之前計劃另一個線程,那該怎麼辦?)。的

+0

嘿,所以我想,dlopen/loadLibrary不會鎖定庫(導致消息如「文件X被程序Y使用」)?一旦lib被加載,整個代碼/數據就在內存中,並且沒有引用剩下的實際文件? – user1228633

+0

@ user1228633當dlopen/loadLibrary將庫加載到內存中時,庫文件中的代碼用於虛擬內存機制。如果有少量空閒的物理內存,操作系統可以從包含庫代碼的內存中卸載一些頁面。但是,如果再次使用庫中的代碼,操作系統將從文件中讀取庫的未加載部分並將其加載回去。當然,如果圖書館沒有關閉,這也是有效的。 –

+0

@ user1228633當操作系統將庫加載到內存中時,庫使用的內存用於全局數據和代碼。您創建的對象數據將放置在內存的其他部分,而所有函數指針都將指向專用於加載庫的內存塊。 –

1

對象是數據而不是代碼。對象的副本是數據的副本,但它仍然指向原始代碼。一旦你卸載了一個動態庫,它的代碼就從內存中消失了,並且任何仍然引用該代碼的對象(即庫提供的類型)都會在它們被要求執行成員函數時遇到麻煩(比如作爲析構函數)。

所以不,不可能卸載一個庫並繼續使用它的代碼。

+1

但是,更積極的一點是,它*可能會加載一個庫,使用它,一旦所有工作完成並刪除所有相關對象,然後卸載庫。我不明白爲什麼你想要什麼就意味着你在使用它之前卸載了庫,這樣可能對你有用。 –