6

我有一个用 C++ 编写的进程外 COM 服务器,它由一些 C# 客户端代码调用。服务器接口之一上的方法向客户端返回一个大的 BSTR,我怀疑这会导致内存泄漏。该代码有效,但我正在寻求有关编组 BSTR 的帮助。

稍微简化一下,服务器方法的 IDL 是

HRESULT ProcessRequest([in] BSTR request, [out] BSTR* pResponse);

并且实现看起来像:

HRESULT MyClass::ProcessRequest(BSTR request, BSTR* pResponse)
{
    USES_CONVERSION;
    char* pszRequest = OLE2A(request);
    char* pszResponse = BuildResponse(pszRequest);
    delete pszRequest;
    *pResponse = A2BSTR(pszResponse);
    delete pszResponse;
    return S_OK;
}

A2BSTR 使用 SysAllocStringLen() 在内部分配 BSTR。

在 C# 客户端中,我只需执行以下操作:

string request = "something";
string response = "";
myserver.ProcessRequest(request, out response);
DoSomething(response);

这是可行的,因为请求字符串被发送到 COM 服务器,并且正确的响应字符串被返回给 C# 客户端。但是每次到服务器的往返都会泄漏服务器进程中的内存。crt 泄漏检测支持显示 crt 堆上没有明显的泄漏,所以我怀疑泄漏是用 IMalloc 分配的。

我在这里做错什么了吗?我发现了一些模糊的评论,即“必须使用 CoTaskMemAlloc 分配所有参数,否则互操作编组器不会释放它们”,但没有详细信息。

安迪

4

3 回答 3

3

我没有看到你的代码有明显的问题。建议您修改 ProcessRequest 方法以排除 COM 互操作作为泄漏源:

HRESULT MyClass::ProcessRequest(BSTR request, BSTR* pResponse)
{
    *psResponse = ::SysAllocStringLen(L"[suitably long string here]");
    return S_OK;
}

我怀疑这不会泄漏,在这种情况下,您已将泄漏范围缩小到您的代码。

我还要注意 OLE2A 在堆栈上分配内存,所以你不仅不应该删除 pszRequest,而且你根本不应该使用 OLE2A,因为堆栈溢出的可能性。有关更安全的替代方案,请参阅本文

我还建议您将 A2BSTR 替换为 ::SysAllocString(CA2W(pszResponse))

于 2009-08-19T14:58:59.757 回答
2

anelson 已经很好地介绍了这一点,但我想补充几点;

  • CoTaskMemAlloc 不是唯一对 COM 友好的分配器——BSTR 被默认编组器识别,并将使用 SysAllocString 和朋友来释放/重新分配。

  • 避免USES_CONVERSION(由于堆栈溢出风险——见anelson的回答),你的完整代码应该是这样的[1]

(请注意,A2BSTR 可以安全使用,因为它在转换后调用 SysAllocString,并且不使用动态堆栈分配。此外,使用 array-delete (delete[]),因为 BuildResponse 可能会分配一个字符数组)

  • BSTR 分配器有一个缓存,可以使它看起来好像存在内存泄漏。有关详细信息,请参阅http://support.microsoft.com/kb/139071,或 Google 了解 OANOCACHE。您可以尝试禁用缓存并查看“泄漏”是否消失。

[1]

HRESULT MyClass::ProcessRequest(BSTR request, BSTR* pResponse)
{
    char* pszResponse = BuildResponse(CW2A(request));
    *pResponse = A2BSTR(pszResponse);
    delete[] pszResponse;
    return S_OK;
}
于 2009-08-19T19:57:59.683 回答
-4

我想你需要request::SysFreeString(). 此内存在服务器端分配。

此外,OLE2A可能会因转换而分配内存(看看)。你也不释放它。

于 2009-08-19T14:29:57.463 回答