【问题标题】:COM memory managementCOM 内存管理
【发布时间】:2011-11-03 23:29:33
【问题描述】:

我有一些关于 COM 内存管理的问题:

  1. 我有一个 COM 方法:

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

结果 = SAFEARRAY(BSTR)。如果我从另一个接口方法收到另一个 SAFEARRAY(BSTR)(为了设置 *result),我是否必须复制收到的字符串以便将它们传递给 *result 和外部客户端?或者考虑到我不会自己使用这些字符串,我可以将它们传递给客户(并传递所有权)?

2.

STDMETHODIMP CWhitelistPolicy::SetWebsitesStrings(SAFEARRAY* input)

在这里,我收到一个 BSTR 数组作为输入。我的方法再次负责输入中分配的内存?

3.

STDMETHOD(SetUsers)(SAFEARRAY* input);

在这里,我在另一个接口 (SetUsers) 上调用一个方法,并为输入 SAFEARRAY 分配内存。在我调用 SetUsers 之后,我可以处理 SAFEARRAY 吗?当编组发生时,内存总是被复制,不是吗? (在我的例子中,SetUsers 方法是在我的进程内作为 COM DLL 托管的接口上调用的)

【问题讨论】:

    标签: memory-management com


    【解决方案1】:

    我认为回答此类问题的方式是考虑跨机器的 COM 调用。然后很明显 [out] 参数;我调用者拥有并且必须释放内存,因为远程封送层无法做到这一点。对于 [in] 参数,很明显封送层必须复制我的数据,而远程封送层再次无法释放我传入的内容。

    COM 的一个核心原则是位置中立,在同一个单元中调用的规则就是跨机器使用 DCOM 时的规则。

    1. 您有责任释放 - 当您调用下一个 fnc 时您不会传递所有权,因为它可能是远程的并且获取的是副本,而不是您的原始数据。

    2. 不 - 作为被调用者,您不必释放它。如果是在公寓内,它是调用者提供的内存,调用者必须释放它。如果是远程调用,服务器存根分配它并在方法返回时释放它。

    3. 是的,你释放它 - 不,它并不总是被复制(它可能是),这就是为什么 2 的答案是否定的。如果它被复制,则会分配一个存根,存根将释放它。

    请注意,我对您问题的回答并未涵盖 [in,out] 参数的情况 - 有关此情况的更多详细信息,请参阅 so 问题 Who owns returned BSTR?

    Com allocation rules 复杂但理性。如果您想了解/查看所有案例的示例,请获取 Don Box 的“essential com”一书。你仍然会犯错误,所以你应该有一个检测它们的策略。我使用 gflags(Windbg 的一部分)及其堆检查标志来捕获双重释放发生时(显示调试消息并在调用 INT 3 时停止执行)。 Vstudio 的调试器曾经在启动可执行文件时为您打开它们(它可能仍然如此),但您可以在图像选项选项卡下使用 gflags 强制它们打开。

    您还应该知道如何使用UMDH(也是windbg 的一部分)来检测泄漏。 DebugDiag 是较新的工具,似乎更易于使用,但遗憾的是,您只能安装 32 位或 64 位版本,但不能同时安装两者。

    问题是 BSTR 被缓存,使得检测双重释放和泄漏变得棘手,因为与堆的交互被延迟了。您可以通过将环境变量OANOCACHE 设置为1 或调用函数SetOaNoCache 来关闭ole 字符串缓存。该函数未在头文件中定义,因此请参阅此 SO 问题 Where is SetOaNoCache defined?。请注意,接受的答案显示了通过 GetProcAddress() 调用它的艰难方法。接受的答案下方的答案显示您只需要一个 extern "C",因为它位于 oleaut32 导出库中。最后,查看thisLarry Osterman 博文,更详细地描述了寻找泄漏时缓存造成的困难。

    【讨论】:

    • 所以对我来说更清楚一点:-) - 我作为输入接收的所有内存(从调用者的角度来看)都不属于我的所有权 - 这是服务器存根的工作.我作为输出传递的所有内存(从调用者的角度来看)都是我的所有权 - 在方法调用之后我必须释放传递的内存,否则它会泄漏。
    • 在您提供的情况下,是的。对于 [in,out] 否,如果您正在修改传入的数据。存根只是在封送调用者之前释放返回的内容,因此如果您想修改传入的内容,则必须释放它。我用其他建议更新了答案,告诉你如何找出错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-21
    • 2012-03-21
    • 1970-01-01
    相关资源
    最近更新 更多