我在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上。
答案 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,一个不太令人愉快的随机函数,具有不可预测的用法。
虽然这肯定是有用的,但程序失败的方式要少得多,但在测试应用程序时实际上并没有用。讨厌,真的,它调用“只能在我的机器上工作”故障模式。呸。