C++ 组件对象模型(COM):iAlloc::Alloc在哪里分配内存?

C++ 组件对象模型(COM):iAlloc::Alloc在哪里分配内存?,c++,winapi,com,dynamic-memory-allocation,C++,Winapi,Com,Dynamic Memory Allocation,正在读取某些遗留项目的COM。到目前为止,我的理解是COM只是一个二进制规范,所有实现组件(客户机和服务器)都必须遵守该规范。只要我们使用只接收和返回简单值类型的方法来处理COM接口,我觉得一切都很有意义 但是,也可以从COM对象向整个对象/变体(包含例如SAFEARRAY)发送指针,我想知道这些param对象的内存分配在哪里。我读到它是windows拥有的内存,我们不应该篡改它,除非通过COM方法。 然后我偶然发现了IMallocCOM接口及其Alloc方法,它似乎以一种COM感知的方式分配了

正在读取某些遗留项目的COM。到目前为止,我的理解是COM只是一个二进制规范,所有实现组件(客户机和服务器)都必须遵守该规范。只要我们使用只接收和返回简单值类型的方法来处理COM接口,我觉得一切都很有意义

但是,也可以从COM对象向整个对象/变体(包含例如
SAFEARRAY
)发送指针,我想知道这些param对象的内存分配在哪里。我读到它是windows拥有的内存,我们不应该篡改它,除非通过COM方法。 然后我偶然发现了
IMalloc
COM接口及其
Alloc
方法,它似乎以一种COM感知的方式分配了大量内存,完美地解决了这一困惑


<>为了不干扰由C++维护的堆结构(假设我们在C++中编写COM服务器),在哪里代码< > IMALC/<代码>分配内存?<我的答案是:我不知道,我不在乎。 但你必须做的是遵守规则。COM(和COM对象)可以自由地以它们选择的任何方式分配内存,而您可能对它们在何处或如何分配内存所做的任何假设都是危险和不必要的。很可能,它最终是通过
HeapAlloc()
分配的,但不需要这样做,即使是这样,您也肯定不知道是哪个堆

当调用COM对象时,客户端(比如说通过CoTaskMemAlloc())分配内存的情况相对较少。更常见的情况是,COM对象分配它所需的内存,以便将调用结果打包,然后返回一个指针(通常以另一个COM对象的形式),您可以使用该指针执行接下来需要执行的任何操作。有问题的方法的API文档将告诉您在使用该指针时要做什么,这就是您需要知道的全部内容。此确切机制因API而异,例如:

  • 对于COM对象调用
    Release()(这通常是隐含的,而不是在文档中显式调用)

  • 对于“原始”指针,文档可能会告诉您调用或
    CoTaskMemFree()
    ,或者
    IMalloc::Free()

  • 对于SAFEARRAY调用
    SafeArrayUnaccessData()
    /
    SafeArrayUnlock()
    /
    SafeArrayDestroy()

  • 有时,您需要调用一些不必要的东西,例如
    SysFreeString()


无论如何-始终-对于任何特定的API,请阅读文档,您应该没有问题。

Windows用于为COM分配创建专用堆,CoTaskMemAlloc()直接从中分配。但是,它在Win8中被删除,现在从默认进程堆进行分配,GetProcessHeap()返回它。VS2012上的Microsoft CRT也发生了更改,以前有自己的堆,但现在也使用默认进程堆


这些改变的确切原因对我来说并不清楚,我从来没有看到一个好的解释。但不太可能与WinRT(又名UWP、又名Windows应用商店、又名现代UI)有关。COM在引擎盖下提供了强大的功能,但通过语言投影提供了非常紧密的语言运行时集成。或者只是为了绕过这些不同堆过去经常造成的麻烦。尤其是CRT堆是一个DLL地狱般的噩梦,当程序在新的VS版本上重建,但仍然使用旧的DLL时,程序会惨遭失败。

你为什么在意?如果您分配了一个SAFAREAR,您将(必须)使用相应的ApsiWeb独立于编程语言,并且可以与各种语言一起使用,因此它不与C++运行时绑定。提供有关接口的一些详细信息。@SimonMourier,我之所以关心,是因为我想理解,而不仅仅是使用。了解内存从何处分配并不是理解COM的重要部分。如果您知道它是从系统提供的私有堆而不是进程的默认堆分配的,您会做什么不同的事情?@RichardChambers:是否复制数据取决于使用的封送拆收器。自定义封送拆收器可以使用共享内存跨进程边界传输数据,而不会引发副本。同样,如果接口指针跨越单元边界,进程内服务器可能仍然需要复制数据。共享同一地址空间没有关系。在COM中,单元边界很重要。@MightyNicM堆的工作方式是请求内存分配,然后由曾经请求它的人拥有。如果你没有要求它,那么你就不拥有它。客户端可以向COM服务器提供指向内存区域的指针,但这不是所有权转移,客户端仍然拥有内存。就进程中的任何特定线程所知,它是唯一一个执行内存分配的线程,而其他线程所做的并不是它真正关心的。所有权转移时可能会发生问题。malloc()在Microsoft CRT中没有任何特殊功能,它直接调用HeapAlloc()。这需要堆句柄,这是Q+A的主题。分配VM是内置堆管理器的工作。@MightyNic的事情是(这就是为什么我像我一样发布的原因)COM内存模型是专门为避免所有这些问题而设计的,这个重要的细节很容易在这里丢失。@MightyNicM:不正确。COM分配器可以安全地分配内存,因为当与相应的
IMalloc::Free
函数一起使用时,它的设计是安全的。实施细节并不重要。它可以使用进程的默认堆、它自己的堆、一些系统堆或其他内存