Memory management COM内存管理

Memory management COM内存管理,memory-management,com,Memory Management,Com,我有一些关于COM内存管理的问题: 我有一个COM方法: STDMETHODIMP CWhitelistPolicy::GetWebsiteStrings(安全数组**结果) 结果=安全阵列(BSTR)。如果我从另一个接口方法接收到另一个SAFEARRAY(BSTR)(为了设置*result),我是否必须复制接收到的字符串,以便将它们传递给*result和外部客户端?或者考虑到我不会为自己使用字符串,我可以将它们传递给客户机(并传递所有权) 二, 这里我接收一个BSTR数组作为输入。同样,我的方

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

  • 我有一个COM方法:

    STDMETHODIMP CWhitelistPolicy::GetWebsiteStrings(安全数组**结果)

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

    二,

    这里我接收一个BSTR数组作为输入。同样,我的方法负责输入中分配的内存

    三,


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

    我认为回答这样的问题的方式是考虑跨机器的COM调用。那么对于一个[out]参数来说,这是显而易见的;因为远程封送层无法完成,所以我必须释放调用者自己的内存。对于[in]参数,显然封送层必须复制我的数据,而远程封送层又无法释放我传入的数据

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

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

  • 否-作为被叫方,您不必释放它。如果是内部单元,则是调用者提供的内存,调用者必须释放内存。如果是远程调用,服务器存根将分配它,并在方法返回时释放它

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

  • 请注意,我对您问题的回答没有涵盖[in,out]参数的情况-有关此情况的更多详细信息,请参阅so问题

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

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


    然后,问题是缓存的BSTR使检测双重释放和泄漏变得棘手,因为与堆的交互延迟。通过将环境变量设置为1或调用函数,可以关闭ole字符串缓存。函数未在头文件中定义,因此请参阅此so问题。注意,接受的答案显示了通过GetProcAddress()调用它的困难方法。下面的答案显示了您所需要的只是一个外部“C”,因为它位于oleaut32导出库中。最后,请参阅Larry Osterman的博客文章,了解查找泄漏时缓存造成的困难的更详细描述。

    因此,让我更清楚一点:-)-我作为输入接收的所有内存(从调用方的角度来看)都不属于我所有-这是服务器存根的工作。我作为输出传递的所有内存(从调用方的角度来看)都是我的所有权-即在方法调用之后,我必须释放传递的内存,否则它将泄漏。在您给出的情况下,是的。对于[in,out],如果您正在修改输入的数据,则不需要。存根只是在封送回调用方之前释放返回的内容,因此如果要修改传入的内容,必须释放它。我用其他的建议更新了答案,关于如何找出你错了的地方。
    STDMETHODIMP CWhitelistPolicy::SetWebsitesStrings(SAFEARRAY* input)
    
    STDMETHOD(SetUsers)(SAFEARRAY* input);