如果它在本地堆上分配,为什么称它为Marshal.AllocHGlobal?

时间:2012-10-08 09:03:01

标签: c# winapi memory-management marshalling

来自Marshal.AllocHGlobal的MSDN文档:

  

AllocHGlobal是Marshal类中的两种内存分配方法之一。此方法从Kernel32.dll公开Win32 LocalAlloc函数。

考虑到有一个GlobalAlloc API在全局堆上分配内存,而不是本地堆,不是这个方法的名字而是误导?

是否有理由将其命名为AllocHGlobal,而不是AllocHLocal

更新:Simon在评论中指出,Windows中不存在全局堆这样的问题,并且GlobalAllocLocalAlloc API仍然用于旧版目的只要。现在,GlobalAlloc API不再是LocalAlloc的包装器。

这解释了为什么API根本不调用GlobalAlloc,但它没有解释为什么API在(不能)使用全局堆时被命名为AllocHGlobal的原因,甚至不打电话给GlobalAlloc。命名不可能是出于遗留原因,因为在删除16位支持之后,直到.NET 2.0才会引入命名。所以,问题仍然存在:为什么Marshal.AllocHGlobal被如此误导地命名?

3 个答案:

答案 0 :(得分:3)

假设您正在使用拖放或剪贴板在应用之间进行数据传输。要填充STGMEDIUM结构,您需要HGLOBAL。所以你打电话给AllocHGlobal。因此这个名字。

此功能的主要用途是与需要HGLOBAL的API互操作。如果它被称为其他任何东西会让人感到困惑,因为当你想要一个HGLOBAL时,你必须找到一些文档来告诉你AllocAnythingElse产生的值可以用作HGLOBAL

答案 1 :(得分:2)

这可以追溯到Windows版本3的旧时代。当时有一个“默认堆”的概念,即从它分配的GlobalAlloc()api函数。从该堆分配的内存可以在所有进程之间共享。

在32位版本的Windows中发生了变化,进程无法再通过堆共享内存。这使得术语“全局堆”和“本地堆”毫无意义。还有一个默认堆的概念,即“进程堆”。 GlobalAlloc()现在从该堆分配。但它不能跨进程边界共享。 GlobalAlloc和Marshal.AllocHGlobal的实际实现使用了LocalAlloc()api函数。另一个Windows 3保留,更适合这些天发生的事情。它反过来在32位Windows上使用HeapAlloc()和GetProcessHeap()。

同意堆使用是一个重要的互操作问题。在您编写的写得不好的C代码中经常出错。返回指向需要由调用者释放的已分配内存的指针的任何此类代码通常会因内存泄漏或访问冲突而失败。这样的C代码从它自己的堆中分配malloc()函数。这是由C运行时库创建的私有堆。你没有希望释放这样的内存,你不知道使用了什么堆,也无法获得CRT堆的句柄。

当C代码使用众所周知的堆时,这只能达到一个好的结果。像进程堆一样。或CoTaskMemAlloc(),由COM代码使用。元帅级别的另一个。请注意,pinvoke marshaller总是在必要时使用CoTaskMemFree()释放内存。如果内存没有分配CoTaskMemAlloc(),那就是Vista上的kaboom,这是XP上的一个无声漏洞。

答案 2 :(得分:1)

我认为你应该阅读https://msdn.microsoft.com/en-us/library/ms810603.aspx

其中一小部分:

  

全局和本地记忆功能乍一看似乎是   Windows中本地和全局内存管理功能纯粹存在   与Windows 3.1版向后兼容。这可能是真的,   但是这些函数的管理与新堆函数一样有效   讨论如下。实际上,从16位Windows移植应用程序   不一定包括从全局和本地内存迁移   堆内存函数的函数。全球和地方的职能   提供相同的基本功能(然后是一些)并且速度一样快   跟...共事。如果有的话,他们可能更方便工作   因为你不必跟踪堆句柄。

     

尽管如此,这些功能的实现并不相同   它适用于16位Windows。 16位Windows有一个全局堆,每个都有   应用程序有一个本地堆。这两个堆管理器实现了   全球和地方职能。通过GlobalAlloc分配内存意味着   在LocalAlloc中从全局堆中检索一块内存   从本地堆分配内存。 Windows现在有一个堆   对于这两种类型的函数 - 上面描述的默认堆。

     

现在你可能想知道两者之间是否有任何区别   本地和全球职能本身。嗯,答案是否定的,他们   现在是一样的。实际上,它们是可以互换的。分配内存   通过调用LocalAlloc可以重新分配GlobalReAlloc和   然后由LocalLock锁定。下表列出了全局和   现在可以使用本地功能。

     

拥有两组完全正常运行的功能似乎是多余的   同样的,但这是向后兼容性的地方。   您是否在16位Windows中使用全局或本地函数   之前的申请并不重要 - 它们同样有效。

等...

此外,记忆力确实很昂贵。另请参阅PostScript语言参考手册,它可以让您深入了解本地/全局内存的使用情况。