Windows环境下的内存分配方法有很多,如VirtualAlloc、HeapAlloc、malloc、new等。
那么,它们之间有什么区别呢?
发布于 2009-05-16 09:57:17
每个API都有不同的用途。当你使用完内存时,每一个都要求你使用正确的释放/释放函数。
VirtualAlloc
这是一个低级的Windows API,它提供了很多选项,但主要适用于特定情况下的用户。只能在(编辑:非4KB)较大的区块中分配内存。有些情况下你需要它,但当你处于其中一种情况时,你就会知道。最常见的一种情况是,您必须直接与另一个进程共享内存。不要将其用于通用内存分配。使用VirtualFree解除分配。
HeapAlloc
分配您请求的任何大小的内存,而不是以比VirtualAlloc更大的块。HeapAlloc知道何时需要调用VirtualAlloc,并自动为您执行此操作。与malloc类似,但仅适用于Windows,并提供了更多选项。适用于分配一般的内存块。一些Windows可能要求您使用它来分配传递给它们的内存,或者使用它的配套HeapFree来释放它们返回给您的内存。
malloc
分配内存的C方法。如果你用C而不是C++编写代码,并且你希望你的代码也能在Unix计算机上运行,或者有人特别告诉你需要使用它,那么你最好使用它。不会初始化内存。适用于分配一般的内存块,如HeapAlloc。一个简单的API。使用free解除分配。Visual C++的malloc调用HeapAlloc。
新的
分配内存的C++方式。如果你是用C++写的,最好是这样。它也会将一个或多个对象放入分配的内存中。使用delete解除分配(或使用delete[]释放数组)。Visual studio的new调用HeapAlloc,然后可能会初始化对象,这取决于您调用它的方式。
在最新的C++标准(C++11及更高版本)中,如果您必须手动使用delete,那么您这样做是错误的,应该使用像unique_ptr这样的智能指针。从C++14开始,new也是如此(被make_unique()等函数取代)。
还有其他几个类似的函数,比如SysAllocString,你可能会被告知在特定情况下必须使用。
发布于 2017-05-19 02:54:26
如果您计划使用需要内存管理的语言(如C或C++),那么理解内存分配API之间的区别(在Windows中)是非常重要的。而最好的解释方式是用图表来说明:

请注意,这是一个非常简化的、特定于Windows的视图。
理解这个图的方法是,内存分配方法在图中的位置越高,它使用的实现级别就越高。但让我们从底部开始。
内核模式内存管理器
它为操作系统提供了所有的内存保留和分配,以及对内存映射文件、共享内存、写入时复制操作等的支持。它不能直接从用户模式代码访问,因此我将跳过这里。
这些是user mode提供的最低级别的API。VirtualAlloc函数主要调用ZwAllocateVirtualMemory,后者会快速到ring0,以便将进一步的处理交给内核内存管理器。这也是在用户模式下从所有可用内存中保留/分配新内存块的最快方法。
但它有两个主要条件:
那么这个系统粒度是多少呢?您可以通过调用GetSystemInfo来获取它。它作为dwAllocationGranularity参数返回。它的值是特定于实现(也可能是硬件)的,但在许多64位Windows系统上,它被设置为0x10000字节或64K。
所有这些都意味着,如果您尝试使用VirtualAlloc分配一个8字节的内存块
void* pAddress = VirtualAlloc(NULL, 8, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);如果成功,pAddress将在0x10000字节边界上对齐。即使您只请求了8个字节,您将获得的实际内存块将是整个page (或类似于4K字节)。确切的页面大小在dwPageSize中返回,但最重要的是,来自pAddress 的跨越0x10000字节(在大多数情况下为64K )的整个内存块将无法用于任何进一步的分配。因此,在某种意义上,通过分配8字节,你也可以要求65536字节。
因此,这里的故事的寓意不是用VirtualAlloc代替应用程序中的通用内存分配。它必须用于非常特殊的情况,就像下面的堆一样。(通常用于保留/分配大的内存块。)
错误地使用VirtualAlloc可能会导致严重的内存碎片。
HeapCreate / HeapAlloc / HeapFree / HeapDestroy
简而言之,堆函数基本上是VirtualAlloc函数的包装器。这里的其他答案提供了一个很好的概念。我会补充说,在一个非常简单的视图中,堆的工作方式是这样的:
HeapCreate通过在内部调用VirtualAlloc (具体地说是ZwAllocateVirtualMemory )保留了一大块虚拟内存。它还设置了一个内部数据结构,可以跟踪保留的虚拟内存块中的更小大小的分配。HeapAlloc和HeapFree的任何调用实际上并不分配/释放任何新的内存(当然,除非请求超过了HeapCreate中已经保留的内存),而是通过将其分解成更小的内存块,将其计量(或commit),用户a反过来调用VirtualFree来实际释放虚拟内存。因此,所有这些都使得堆函数成为应用程序中通用内存分配的理想候选者。它非常适合任意大小的内存分配。但是,为方便使用堆函数而付出的一个小代价是,在保留较大的内存块时,堆函数会引入比VirtualAlloc略高的开销。
堆的另一个好处是你并不真正需要创建它。它通常是在进程启动时为您创建的。所以我们可以通过调用GetProcessHeap函数来访问它。
malloc /免费
是堆函数的特定于语言的包装器。与HeapAlloc、HeapFree等不同的是,这些函数不仅适用于Windows,而且适用于其他操作系统(如Linux等)。
如果您用C语言编程,这是一种分配/释放内存的推荐方法(除非您正在编写特定的内核模式设备驱动程序)。
new / delete
作为一个高级的(好吧,对于C++)内存管理操作员。它们是特定于C++语言的,就像C的malloc一样,它们也是heap函数的包装器。他们也有一大堆自己的代码来处理构造函数的C++-specific初始化,解构函数中的释放,引发异常等。
如果您在C++中编程,建议使用这些函数来分配/释放内存和对象。
最后,我想对其他关于使用VirtualAlloc在进程之间共享内存的回复中所说的内容做一个评论。VirtualAlloc本身不允许与其他进程共享其保留/分配的内存。为此,需要使用应用程序接口来创建可与其他进程共享的命名虚拟内存块。它还可以将磁盘上的文件映射到虚拟内存中进行读/写访问。但这是另一个话题。
发布于 2009-05-16 09:44:14
在大纲中:
https://stackoverflow.com/questions/872072
复制相似问题