LocalAlloc Vs GlobalAlloc Vs malloc Vs new

LocalAlloc Vs GlobalAlloc Vs malloc Vs new

本文关键字:Vs new malloc GlobalAlloc LocalAlloc      更新时间:2023-10-16

我已经在各种链接上搜索过了,但仍然存在疑问。

我不理解LocalAllocGlobalAllocmallocnew在内存分配方面的区别。

我已经浏览了MSDN的这个链接:

内存分配方法的比较

请解释以下声明:

malloc函数的缺点是依赖于运行时。运算符的缺点是依赖于编译器和语言的

陈的OldNewThing 节选

在16位Windows时代,这种差异是显著的。

在16位Windows中,内存是通过名为"选择器",每个选择器最多可寻址64K。有一个默认选择器称为"数据选择器";对所谓"近指针"是相对于数据选择器执行的。对于例如,如果您有一个值为0x1234的近指针p数据选择器是0x012F,然后当您写入*p时,您正在访问012F:1234的存储器。(当你声明一个指针时,它就在附近违约如果你想要一个远指针,你必须明确地说FAR。)

重要提示:近指针通常相对于选择器数据选择器。

GlobalAlloc函数分配了一个选择器,该选择器可用于访问您请求的内存量。你可以访问内存在带有"远指针"的选择器中。"远指针"是一个选择器与近指针相结合。(请记住,近距离指针是相对于选择器;当您将近端指针与适当的选择器,您会得到一个远指针。)

程序和DLL的每个实例都有自己的数据选择器作为HINSTANCE。因此,如果您有一个接近指针p并访问它通过*p从程序可执行文件访问内存程序实例的HINSTANCE。如果您从DLL访问它获得了相对于DLL的HINSTANCE的内存。

因此,在16位Windows中,LocalAlloc和GlobalAlloc功能完全不同!LocalAlloc返回了一个近指针,而GlobalAlloc返回了一个选择器。

打算在模块之间传递的指针必须位于形式的"远指针",因为每个模块都有不同的默认值选择器。如果您想将内存的所有权转移给其他人模块,您必须使用GlobalAlloc,因为这允许收件人调用GlobalFree来释放它。

即使在Win32中,也必须小心不要混淆本地堆来自全局堆。无法在上释放从中分配的内存另外所有关于远近指针的怪异都随着向Win32的转换。但是本地堆函数和全局然而,堆函数是两个不同的堆接口。

此外,你指定的链接清楚地表明,

从32位Windows开始,GlobalAlloc和LocalAlloc是实现为使用句柄调用HeapAlloc的包装函数进程的默认堆,并且可以指示HeapAlloc提升如果无法分配内存,则为异常,如果无法LocalAlloc提供。

对于您对malloc与new的困惑,Billy ONeal的回答非常清楚地总结了这一点。

对于malloc和HeapAlloc之间的差异,David Heffernan和Luis Miguel Huapaya的回答结合起来给出了完美的解决方案:

  • malloc是可移植的,是标准的一部分。malloc(和其他C运行时堆函数)是依赖于模块的,这意味着如果您在一个模块(即DLL)的代码中调用malloc,那么您应该在同一模块的代码内调用free,否则您可能会遭受一些非常严重的堆损坏
  • HeapAlloc不是可移植的,它是一个Windows API函数。使用HeapAllocGetProcessHeap代替malloc,包括重载newdelete运算符来利用它们,允许您在模块之间传递动态分配的对象,并且当指向内存块的指针传递到外部模块时,如果在一个模块的代码中分配内存,而在另一个模块中释放内存,则无需担心内存损坏

GlobalAllocLocalAlloc是16位时代的旧函数。不同的是,您有时必须能够分配仅在您的段中使用的内存(使用近指针),有时还需要分配与系统上的其他进程和段共享的内存。今天,这些人以某种形式转发到HeapXxx函数,例如HeapAlloc。如果您正在编写新代码,并且需要避免与C运行时链接,则应该使用HeapXxx函数。当然,如果您调用其中任何一个,您的程序将只能在Windows上编译和运行。

malloc是"依赖于运行时的",因为使用它需要链接到C运行时(CRT)。CRT是包含所有其他标准C库函数的库,如printfqsort。你可以编写一个简单的Win32 API程序,而不需要与之链接(但我真的不明白你为什么要在真正的软件中这样做)。

new依赖于编译器和语言,因为它们需要一个能够编译C++的编译器。(通常new是根据malloc实现的,因此可能也需要使用CRT)