CoTaskMemAlloc v malloc v AllocHGlobal

时间:2016-04-05 08:14:34

标签: c# c winapi pinvoke

我在Windows上看过,malloc与CoTaskMemAlloc不同,后者与AllocHGlobal不同。对于C#使用者来说,这可能意味着如果我有一个返回malloc指针的C函数,我需要在其上调用free。如果我P / Invoke并指定一个字符串返回类型,CLR应该调用CoTaskMemFree并且应该在malloc指针上失败。

然而,我在实践中无法看到这一点。我创建了一个DLL,它只返回一个malloc'd char *和P / Invoked它作为一个字符串。没有内存泄漏。实际上,无论我尝试什么,我都无法让事情失败。我调用malloc,GlobalHAlloc,CoTaskMemAlloc,然后使用任何免费的实现,只是工作。没有内存泄漏。重新使用相同的内存空间。

如何强制失败?或者这是那些应该是“实现定义”的东西,但实际上只是单向工作?

这是在VS2015 Update 2,Windows 8.1上。

1 个答案:

答案 0 :(得分:6)

这当然不习惯。但事情一直在变化。 C运行时库was changed in VS2012,它不再创建自己的堆。对于VS2015,此代码在C:\ Program Files(x86)\ Windows Kits \ 10 \ Source \ 10.0.10240.0 \ ucrt \ heap \ heap_handle.cpp中是相关的:

// Initializes the heap.  This function must be called during CRT startup, and
// must be called before any user code that might use the heap is executed.
extern "C" bool __cdecl __acrt_initialize_heap()
{
    __acrt_heap = GetProcessHeap();
    if (__acrt_heap == nullptr)
        return false;

    return true;
}

注意对GetProcessHeap()的调用,它返回Marshal.AllocHGlobal()分配的相同堆。所以是的,当您使用Marshal.FreeHGlobal()取消分配时,您不会从调试堆中获得异常,也不会泄漏。

CoTaskMemAlloc()大致相同。单步进入该功能,我看到:

7638D1E1  mov         esi,dword ptr [g_CMalloc (76485EE0h)]  
7638D1E7  push        dword ptr [ebp+8]  
7638D1EA  mov         esi,dword ptr [esi+0Ch]  
7638D1ED  cmp         esi,offset CRetailMalloc_Alloc (763732C0h)  
7638D1F3  jne         CoTaskMemAlloc+44h (7638D214h)  
7638D1F5  push        0  
7638D1F7  push        dword ptr [g_hHeap (76485E68h)]  
7638D1FD  call        dword ptr [__imp__HeapAlloc@12 (76488228h)] 

请注意g_hHeap变量的用法。我看到它与GetProcessHeap()返回的值相同。再次,使用任何释放函数释放将会正常工作。

请注意,我从Windows 10获得此版本,Windows的旧版本不会以相同的方式运行。并注意CRetailMalloc_Alloc,一个不太令人愉快的随机函数,具有不可预测的用法。

虽然这肯定是有用的,但程序失败的方式要少得多,但在测试应用程序时实际上并没有用。讨厌,真的,它调用“只能在我的机器上工作”故障模式。呸。