2009-04-11 40 views
2

我在一些應用程序中有很多引用計數類,而且在那些應用程序使用的dll中,它們都繼承並實現了一個IRefCounted接口。C++:調試引用計數系統中的內存泄漏

爲了幫助找到這些內存泄漏的來源,我希望每個應用程序都維護存在的所有這些參考計數類的列表。

問題是管理這些列表的實例,使它們的用途不影響我的類的使用(例如,我不需要將指針傳遞給列表的所有時間,而是以某種方式將它附加到該過程)。

-Theres很好的機會,這些應用程序中的幾個可能一次運行,並使用相同的DLL。每個應用程序都需要自己的對象列表,並且該應用程序加載的所有dll等都需要使用該列表(但要注意一個dll可能會被多個應用程序加載...)。
- 該列表必須在應用程序中的每個其他全局變量和靜態變量之後銷燬,因此列表中的對象在被破壞時留在列表中的對象未被正確釋放。

然後,我會簡單地添加一個斷點到列表的析構函數,這樣我就可以查看調試器中的任何未分配的對象。

+0

對不起,你的問題是? – 2009-04-11 13:49:21

回答

1

我猜你正在使用COM。您可能需要找到某種方式讓weak pointer以便實例化對象的註冊表不會被破壞。

如果您可以修改所有類,則可以注入一個靜態成員來跟蹤所有實例,並讓實例的析構函數將其自身從靜態成員中移除。例如,你可以使用一個基類或實用類像下面這樣:

class InstanceRegistry { 
protected: 
    InstanceRegistry() { 
     registry.insert(this); 
    } 
    ~InstanceRegistry() { 
     registry.remove(this); 
    } 
private: 
    static SomeContainerType<InstanceRegistry*> registry; 
}; 

額外的工作需要,如果你想爲不同類型的類不同的註冊表做,等

+0

我沒有使用COM,我可以添加一些東西到對象的con/destructor中以添加從列表中刪除它們。列表probs不應該有對象的引用。 – 2009-04-11 16:02:52

+0

COM使用IUnknown,而不是IRefCounted。 – 2009-04-11 16:07:33

1

如果進程正在使用相同的DLL,每個進程都會獲得該DLL的靜態(或「全局」)數據的私有副本。

所以你需要做的就是使列表成爲一個DLL中的全局變量,並從每個應用程序鏈接到該DLL。這樣,就不需要傳遞任何附加信息。

由於多DLL過程中對象的毀壞順序的不可預測性,您陷入困境的想法充滿了困難。

mainWinMain函數的末尾轉儲列表的內容會簡單很多。

如果您沒有以一致的方式使用智能指針類,那就這樣做。此外,它可能值得尋找循環引用計數 - 對象A有對象B的計數,反之亦然。這是未發佈對象的常見原因。

更新:

要強制所有的靜態析運行和釋放對象,這樣,那麼你可以檢查列表中的條目之後,你需要構建應用程序以某種方式。

假設您有一個非常小的EXE來啓動進程,並加載了許多其他可以完成所有工作的DLL。這些其他DLL以某種方式(可能通過COM或COM類系統)以LoadLibrary加載。 LoadLibrary API的工作方式是將DLL加載到進程中,或者在DLL已經加載的情況下遞增DLL上的內部引用計數器。 FreeLibrary API遞減計數器直到達到零,然後卸載DLL(此時將執行該DLL的靜態析構函數)。

爲此,我們現在添加我們的診斷DLL,其中包含所有未完成引用計數對象的列表。所有其他DLL使用import-lib鏈接到診斷DLL,EXE也使用LoadLibrary。

main即將退出的EXE經過DLL列表處理它以前加載,並在所有這些調用FreeLibrary則。通過保持加載診斷DLL,它確保它仍然在那裏。至少這是理論。

但是按照什麼順序應該卸載其他DLL?如果A.DLL具有指向B.DLL中定義的對象的靜態指針,那麼您最好首先卸載A.因此,您需要了解各種DLL如何形成「分層」體系結構,其中較高層依賴於較低層,從而爲您提供卸載它們的安全順序。另外,一旦卸載了所有的DLL,診斷列表中任何引用DLL中對象的條目現在都將指向堆上的有效數據,但vtable將指向已定義的代碼通過現在已經卸載的DLL,所以你將無法調用這些對象的虛函數。你應該能夠檢查他們的數據。