2011-08-25 73 views
3

我有一個關於COM的內存管理的一些問題:COM內存管理

  1. 我有一個COM方法:

    STDMETHODIMP CWhitelistPolicy :: GetWebsitesStrings(SAFEARRAY **結果)

結果= SAFEARRAY(BSTR)。如果我從另一個接口方法(爲了設置*結果)接收到另一個SAFEARRAY(BSTR),是否必須複製接收到的字符串以將它們傳遞給* result和outside client?或者考慮到我不會爲自己使用這些字符串,我可以將它們傳遞給客戶(並傳遞所有權)?

2.

STDMETHODIMP CWhitelistPolicy::SetWebsitesStrings(SAFEARRAY* input) 

在這裏,我接收BSTR陣列作爲輸入。我的方法再次負責輸入中分配的內存?

3.

STDMETHOD(SetUsers)(SAFEARRAY* input); 

在這裏,我調用另一個接口(SetUsers)上的方法和我的輸入SAFEARRAY分配內存。在我打電話給SetUsers後,我可以處理SAFEARRAY?記憶總是在編組時發生,不是嗎? (在我的情況下,SetUsers方法在作爲我的進程內的COM DLL託管的接口上調用)

回答

3

我認爲回答這種問題的方式是考慮一個跨越機器的COM調用。那麼這對於一個[out]參數來說是顯而易見的。我是調用者自己的,並且必須釋放內存,因爲遠程封送層無法執行此操作。對於[輸入]參數,很顯然,封送層必須複製我的數據,並且遠程封送層再次無法釋放我傳入的內容。

COM中的核心原則是位置中立,調用時的規則相同公寓是跨機器使用DCOM的規則。

  1. 你負責釋放 - 當你調用下一個FNC因爲它可能是遠程和得到一個副本,而不是原來的數據不傳遞所有權。

  2. 否 - 作爲被調用者,您不必釋放它。如果是公寓內部,則是主叫方提供的內存,並且主叫方必須將其釋放。如果是遠程調用,服務器存根分配它並在方法返回時釋放它。

  3. 是的,你釋放它 - 不,它並不總是被複制(它可能是),這就是爲什麼對2的答案是否定的。如果它被複制,就會有一個存根分配,存根將釋放它。

注意我的回答您的問題沒有涵蓋的情況下[IN,OUT]參數 - 看到如此質疑Who owns returned BSTR?這個案件的更多細節。

Com allocation rules很複雜但是合理。如果您想了解/查看所有案例的示例,請通過Don Box獲取「基本com」一書。你仍然會犯錯誤,所以你應該有一個檢測它們的策略。我使用gflags(Windbg的一部分)及其堆檢查標誌來捕獲何時發生雙重空閒(調試消息在INT 3調用時顯示和執行停止)。Vstudio的調試器在啓動可執行文件時曾經爲你打開它(它可能仍然存在),但你可以在圖像選項選項卡下用gflags強制它們。

您還應該知道如何使用UMDH(也是windbg的一部分)來檢測泄漏。 DebugDiag是最新的工具,似乎更易於使用,但遺憾的是,您只能安裝32位或64位版本,但不能同時安裝。

接下來的問題是緩存的BSTRs會檢測到雙重空閒和泄漏,因爲與堆交互延遲。您可以通過將環境變量OANOCACHE設置爲1或調用函數SetOaNoCache來關閉ole字符串緩存。該函數沒有在頭文件中定義,所以看到這個問題Where is SetOaNoCache defined?。注意接受的答案顯示了通過GetProcAddress()調用它的困難方法。答案低於接受的答案顯示所有你需要的是一個extern「C」,因爲它在oleaut32的輸出庫中。最後,請參閱this Larry Osterman博客文章,以獲取有關緩存在尋找泄漏時所造成困難的更詳細說明。

+0

所以對我來說應該更清楚一點:-) - 作爲輸入接收的所有內存(從調用者的角度來看)不在我的所有權 - 這是服務器存根的工作。我作爲輸出傳遞的所有內存(從調用者的角度來看)都是我的所有權 - 即在方法調用之後,我必須釋放傳遞的內存,否則它會泄漏。 – Ghita

+0

在你提供的情況下,是的。對於[in,out],如果你正在修改已經進入的數據,那麼存根就會釋放返回調用者之前返回的內容,所以如果要修改進來的內容,就必須釋放它。我更新了有關如何確定何時出錯的其他建議的答案。 –