malloc()和HeapAlloc()的区别

68

malloc()和HeapAlloc()之间有什么区别?据我了解,malloc从堆中分配内存,就像HeapAlloc一样,对吗?

那么它们有什么不同呢?

8个回答

97

实际上,malloc()(以及其他C运行时堆函数)是模块依赖的,这意味着如果你在一个模块的代码中调用malloc()(例如DLL),那么你应该在同一模块的代码中调用free(),否则你可能会遭受一些相当严重的堆破坏(这已经有充分的文档记录)。使用HeapAlloc()和GetProcessHeap()代替malloc(),包括重载new和delete操作符来使用它们,可以让你在动态分配对象之间传递参数而不必担心内存损坏,即使在一个模块的代码中分配了内存并在另一个模块的代码中释放了指向内存块的指针。


18
最重要的答案在这里。malloc()是可移植的,但当你需要移动对象并涉及到DLL时,你需要使用堆(Heap)。对于Windows开发者来说,建议使用堆,并为堆编写自定义STL分配器。 - CodeAngry
这个异议仍然有效吗?例如,VC 2013 CRT将_crtheap初始化为GetProcessHeap(),因此来自不同DLL的malloc/free应该已经使用相同的GetProcessHeap()。如果混合“发布”和“调试”CRT,则情况就不同了。后者会向返回的指针添加偏移量,因此确实通过调试版本分配并通过发布版本释放(或反之亦然)将导致程序崩溃。 - isti_spl
9
请提供您所提到的“有充分文献支持”的链接,谢谢。 - the_endian

61
您说得没错,它们都从堆中分配内存。但是它们之间有所不同:
  • malloc()是可移植的,是标准库的一部分。
  • HeapAlloc()不是可移植的,它是Windows API函数。
在Windows上,malloc很可能是基于HeapAlloc实现的。我希望mallocHeapAlloc更快。 HeapAllocmalloc更具灵活性。特别是它允许您指定要从哪个堆中分配内存。这适用于每个进程的多个堆的情况。 对于几乎所有的编码场景,您都应该使用malloc而不是HeapAlloc。尽管由于您标记了您的问题为C ++,我预计您将使用new

40
如果malloc是在HeapAlloc的基础上实现的,那么它怎么可能比HeapAlloc更快呢? - dan04
13
因为malloc可能会实现进一步的子分配模式。 - David Heffernan
9
“陷阱针对缺乏经验的开发人员”可以;“没有其他用途”,不完全正确。您可以将其与每个线程的堆栈或从可执行堆中分配内存一起使用。 - user7116
9
它还有其他的用途,比如在除了C或C++之外的其他语言中使用。实际上,使用C或C++编程的程序员并不占多数。 - Sheng Jiang 蒋晟
31
@drhirsh说的是Microsoft在这里所做的与其他平台没有什么不同;malloc()函数很少(或从未)由操作系统直接提供,而是由C库根据底层操作系统原语实现。在Win32上,它是HeapAlloc();在Unix上,malloc()通常基于sbrk()或mmap()实现。文件也存在类似的情况:C的fopen()函数是基于Win32的CreateFile()或Unix的open()实现的。OP的问题实际上类似于“fopen() vs open()”或“fopen() vs CreateFile()”。 - BrendanMcK
显示剩余5条评论

30

使用Visual C++,函数malloc()或运算符new最终调用HeapAlloc()。如果您对代码进行调试,将找到文件malloc.c中的函数_heap_alloc_base()调用return HeapAlloc(_crtheap, 0, size),其中_crtheap是使用HeapCreate()创建的全局堆。

函数HeapAlloc()在最小化内存开销方面做得很好,每个分配的最小开销为8字节。我见过的最大开销为每个分配15字节,适用于从1字节到100,000字节的分配。更大的块有更大的开销,但作为有效负载的总分配的百分比仍然低于2.5%。

我无法评论性能,因为我没有使用自定义程序测试过HeapAlloc(),但就使用HeapAlloc()的内存开销而言,开销非常低。


3
HeapAlloc() 和 HeapFree() 调用了在 ntdll.dll、kernel32.dll 和 kernalebase.dll 中实现的 RtlHeapAlloc()。 - Phiber
我在我的开放地址哈希映射 http://sourceforge.net/projects/cgenericopenaddresshashmap/ 中有一个基准测试,表明Windows 8的malloc至少比Windows 7快5倍。有人在这里建议(http://www.gamedev.net/topic/669459-massive-allocation-perf-difference-between-win8-win7-and-linux/)MS CRT malloc仅仅是包装了HeapAlloc,你确认吗? - v.oddou

7

malloc 是C标准库(也包括C++标准库)中的函数。

HeapAlloc 是Windows API函数。

后者允许您指定要分配内存块的堆,这对于避免在不同线程中序列化分配请求可能很有用(注意 HEAP_NO_SERIALIZE 标志)。


3
在涉及到多个DLL可能会被加载和卸载的系统中(通过LoadLibrary/Freelibrary),并且当内存可能在一个DLL中分配,但在另一个DLL中释放(参见前面的答案),HeapAlloc和相关函数似乎是成功共享内存的最小公倍数。
线程安全,被假定为由许多博士高度优化过的HeapAlloc似乎能在我们那些不太可共享的使用malloc/free的代码失败的各种情况下工作。
我们是一个C++嵌入式商店,因此我们在整个系统中重载了operator new/delete运算符,以使用HeapAlloc(GetProcessHeap()),该函数可以在目标上存根或本地(对于Windows)以实现代码可移植性。
现在我们已经绕过了malloc/free,这些函数似乎是特定于DLL的,每个DLL加载都会创建一个新的“堆”,所以迄今为止没有任何问题。

1
此句话的英译中文为:“此外,您还可以参考以下内容:”(保留了HTML标签,不做解释)

https://msdn.microsoft.com/en-us/library/windows/desktop/aa366705(v=vs.85).aspx

这意味着您可以启用WinApi内存分配器管理的HEAP的某些功能,例如“HeapEnableTerminationOnCorruption”。
据我所知,它提供了一些基本的堆溢出保护措施,从安全角度考虑,这可能被视为应用程序的附加价值。
例如,作为应用程序所有者,我更愿意使我的应用程序崩溃,而不是执行任意代码。
另一个好处是,在开发的早期阶段使用它可能很有用,因此您可以在进入生产之前捕获内存问题。

-1

malloc是由C运行时库(CRT)导出的函数,其特定于编译器。
C运行时库DLL名称随Visual Studio版本而变化。

HeapAlloc函数由位于Windows文件夹中的kernel32.dll导出。


-2

这是微软对此的说法:http://msdn.microsoft.com/en-us/library/windows/desktop/aa366533(v=vs.85).aspx

迄今为止,有一件事情没有被提到:“malloc函数的缺点是运行时依赖性。new操作符的缺点是编译器依赖性和语言依赖性。”

另外,“HeapAlloc可以被指示在无法分配内存时引发异常”。

因此,如果您希望您的程序能够在任何CRT上运行,或者可能根本不使用CRT,则应使用HeapAlloc。也许只有恶意软件编写者才会这样做。另一个用途可能是,如果您正在编写一个非常占用内存的应用程序,并且具有特定的内存分配/使用模式,您可能会编写自己的堆分配器,而不是使用CRT的堆分配器。


我知道我晚了十年,但是有很多好的理由让你想直接使用HeapAlloc。最明显的是每个全局分配器都有一个锁 - 从主内存源中拥有一个单独的内存源可以使争用最小化。你甚至可以禁用内部锁,并根据代码的特定需求提供自定义同步来管理HeapAlloc。 - nfries88

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接