我已经在各种链接上搜索过这个,但仍然存在疑问。
对于内存分配,我不理解LocalAlloc
与GlobalAlloc
与malloc
vs new
之间的区别。
我已经浏览了MSDN的这个链接:
Comparing Memory Allocation Methods
请解释以下声明:
malloc 函数的缺点是依赖于运行时。 new 运算符的缺点是依赖于编译器和语言相关
答案 0 :(得分:21)
回到16位Windows的时代,差异很大。
在16位Windows中,通过调用的值访问内存 “选择器”,每个可以解决高达64K的问题。有一个 默认选择器称为“数据选择器”;所谓的操作 相对于数据选择器执行“近指针”。对于 例如,如果你有一个近指针p,其值为0x1234而你的 数据选择器是0x012F,然后当你写* p时,你正在访问 内存在012F:1234。 (当你声明一个指针时,它就在附近 默认。如果你想要一个远指针,你必须明确地说FAR。)
重要说明:通常,近指针总是相对于选择器 数据选择器。
GlobalAlloc函数分配了一个可用于的选择器 访问您请求的内存量。你可以访问内存 在那个带有“远指针”的选择器中。 “远指针”是一个选择器 结合近指针。 (请记住,近指针是 相对于选择器;当你将近指针与一个组合时 适当的选择器,你得到一个远指针。)
程序和DLL的每个实例都有自己的数据选择器,已知 作为HINSTANCE。因此,如果你有一个近指针p并被访问 它通过* p从程序可执行文件,它访问内存相对于 程序实例的HINSTANCE。如果你从DLL访问它,你 得到了相对于你的DLL的HINSTANCE的记忆。
因此,在16位Windows中,LocalAlloc和GlobalAlloc 功能完全不同! LocalAlloc返回了附近 指针,而GlobalAlloc返回一个选择器。
您打算在模块之间传递的指针必须在 “远指针”的形式,因为每个模块都有不同的默认值 选择。如果您想将内存的所有权转移到另一个 模块,你必须使用GlobalAlloc,因为这允许收件人 致电GlobalFree来解冻它。
即使在Win32中,也必须小心不要混淆本地堆 来自全局堆。从一个分配的内存无法释放 其他。所有关于远近指针的怪异都消失了 过渡到Win32。但是本地堆函数和全局 堆函数仍然是两个不同的堆接口。
此外,您指定的link清楚地说明了,
从32位Windows开始,GlobalAlloc和LocalAlloc都是 实现为使用句柄调用HeapAlloc的包装函数 进程的默认堆,可以指示HeapAlloc引发 如果无法分配内存,则异常,但不是 可以使用LocalAlloc。
对于你对 malloc vs new 的困惑,Billy ONeal的回答非常清楚地总结了这一点。
对于 malloc and HeapAlloc 之间的区别, David Heffernan和Luis Miguel Huapaya的答案结合起来提供了完美的解决方案::
malloc
是便携式的,是标准的一部分。 malloc
(以及其他C运行时堆函数)与模块有关,这意味着如果从一个模块(即DLL)中调用代码中的malloc
,则应在代码中调用free
相同的模块或你可能会遭受一些非常糟糕的堆损坏。HeapAlloc
不可移植,它是Windows API函数。使用HeapAlloc
与GetProcessHeap
代替malloc
,包括重载new
和delete
运算符以使用此类运算符,允许您在模块之间传递动态分配的对象如果内存块在一个模块的代码中分配,并且一旦指向内存块的指针传递到外部模块,则不必担心另一个模块的代码中释放内存损坏。答案 1 :(得分:16)
GlobalAlloc
and LocalAlloc
are old functions from the 16 bit era.不同之处在于您有时必须能够分配仅在您的段中使用的内存(使用近指针),有时需要分配内存以与系统上的其他进程和段共享。今天,这些人以某种形式转发到HeapXxx函数,例如HeapAlloc
。如果您正在编写新代码并且需要避免与C运行时链接,则应使用HeapXxx函数。当然,如果您调用其中任何一个,您的程序将只能在Windows上编译和运行。
malloc
是“运行时相关的”,因为使用它需要您链接C运行时(CRT)。 CRT是包含所有其他标准C库函数的库,如printf
或qsort
。您可以编写一个简单的Win32 API程序,而无需与此链接(但老实说,我不明白为什么您希望在真实软件中执行此操作)。
new
依赖于编译器并且依赖于语言,因为它们需要可以编译C ++的编译器。 (通常new
是按malloc
实现的,所以它可能也需要使用CRT)