Windows环境下分配内存的方法有很多,例如 VirtualAlloc, HeapAlloc, malloc, new.

那么,它们之间有什么区别呢?

有帮助吗?

解决方案

每个API是用于不同的用途。每个人还要求你使用正确释放/释放功能,当你与内存中完成。

虚拟

一个低级别的Windows API,它提供了很多的选择,但对人相当具体情况主要是有用的。更大的块:只能在(未4KB编辑)分配内存。在有些情况下你需要它的情况,但是当你在这些情形之一是,你就知道了。其中最常见的是,如果你有直接与另一个进程共享内存。不要使用它的通用内存分配。使用VirtualFree解除分配。

HeapAlloc

任何分配的内存大小,你要求的不是在大块比VirtualAllocHeapAlloc知道什么时候需要调用VirtualAlloc并自动为你这样做。像malloc,但只有Windows版本,并提供了一些更多的选择。适用于分配的内存块一般。一些Windows的API可能会要求您使用此分配,你传递给他们,或使用其同伴HeapFree以释放内存,他们回报给你的记忆。

的malloc

分配存储器的C-方式。喜欢这个,如果你在写C而不是C ++,你想你的代码如上工作Unix计算机过,或者有人专门说您需要使用它。没有初始化的内存。适用于分配的内存块一般,像HeapAlloc。一个简单的API。使用free解除分配。视觉C ++的malloc呼叫HeapAlloc

分配存储器的C ++方法。喜欢这个,如果你用C ++编写。它把一个或多个对象到所分配的内存了。使用delete取消分配(或delete[]数组)。 Visual Studio的new电话HeapAlloc,然后也许初始化的对象,这取决于你如何称呼它。

在最近的C ++标准(C ++ 11及以上),如果你有手动使用delete,你这样做是错误的,应该使用的智能指针的像unique_ptr代替。从C ++ 14日起,同样,可以说new的(置换函数,如make_unique())。


也有几个像SysAllocString其他类似的功能,你可能会告诉你,在特定情况下使用。

其他提示

VirtualAlloc 是操作系统虚拟内存(VM)系统的专门分配。VM系统中的分配必须以与体系结构相关的分配粒度进行。VM系统中的分配是最基本的内存分配形式之一。VM 分配可以采用多种形式,内存不一定是专用的或物理支持在 RAM 中(尽管可以)。VM 分配通常是 特殊目的 分配类型,要么因为分配必须

  • 非常大,
  • 需要分享,
  • 必须与特定值保持一致(性能原因)或
  • 调用者不需要立即使用所有这些内存......
  • ETC...

HeapAlloc 本质上是什么 mallocnew 两者最终都打电话。它被设计为非常快速且可在通用分配的许多不同类型的场景下使用。它是经典意义上的“堆”。堆实际上是由 VirtualAlloc, ,这就是习惯 最初 从操作系统保留分配空间。空间初始化后 VirtualAlloc, 、各种表、列表和其他数据结构被配置来维护和控制HEAP的操作。其中一些操作的形式是动态调整堆大小(增长和收缩)、使堆适应特定用途(某些大小的频繁分配)等。

newmalloc 都有些相同, malloc 本质上是一个精确的调用 HeapAlloc( heap-id-default ); new 但是,可以[另外]为 C++ 配置分配的内存 物体. 。对于给定的对象,C++ 将为每个调用者在堆上存储 vtable。这些虚函数表是执行重定向,并构成了 C++ 的 OO 特性的一部分,例如继承、函数重载等......

其他一些常见的分配方法,例如 _alloca()_malloca() 基于;FileMappings 确实分配了 VirtualAlloc 并设置特定的位标志,指定这些映射的类型 FILE.

大多数时候,您应该以与该内存的使用一致的方式分配内存;)。 new 在 C++ 中, malloc 对于C, VirtualAlloc 适用于大规模或 IPC 案例。

*** 注意,大内存分配由 HeapAlloc 实际上被运送到 VirtualAlloc 经过一定的大小(几百k或16MB或我忘记的东西,但相当大:))。

***编辑我简短地评论了IPC和 VirtualAlloc, ,还有一些相关的非常巧妙的东西 VirtualAlloc 这个问题的回答者都没有讨论过。

VirtualAlloc前任 是一个进程可以用来在一个地址空间中分配内存的方法 不同的 过程。最典型的是,这被使用 结合 通过以下方式在另一个进程的上下文中获得远程执行 创建远程线程 (如同 CreateThread, ,线程只是在另一个进程中运行)。

如果您计划使用需要内存管理的语言(例如 C 或 C++),那么了解内存分配 API(在 Windows 中)之间的区别非常重要。恕我直言,说明它的最佳方法是用图表:

enter image description here

请注意,这是一个非常简化的 Windows 特定视图。

理解该图的方法是,图中的内存分配方法越高, 更高层次 它使用的实现。但让我们从底部开始。

内核模式内存管理器

它为操作系统提供所有内存预留和分配,并支持 内存映射文件, 共享内存, 写时复制 操作等它无法从用户模式代码直接访问,因此我将在这里跳过它。

虚拟分配 / 虚拟免费

这些是 最低级别 可从以下 API 获取 用户模式. 。这 VirtualAlloc 函数基本上调用 Zw分配虚拟内存 这反过来又快速地 系统调用ring0 将进一步的处理委托给内核内存管理器。它也是从用户模式下所有可用内存中保留/分配新内存块的最快方法。

但它有两个主要条件:

  • 它仅分配在系统粒度边界上对齐的内存块。

  • 它仅分配大小为系统粒度倍数的内存块。

那么这是什么 系统粒度?您可以通过致电获取 获取系统信息. 。它返回为 dwAllocationGranularity 范围。它的值是特定于实现(也可能是硬件)的,但在许多 64 位 Windows 系统上它被设置为 0x10000 字节,或 64K.

所以这一切意味着,如果你尝试分配一个 8 字节内存块 VirtualAlloc:

void* pAddress = VirtualAlloc(NULL, 8, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

如果成功的话, pAddress 将对齐在 0x10000 字节边界。即使您只请求 8 个字节,您将获得的实际内存块将是整个内存块 page (或者,类似的东西 4K 字节。准确的页面大小返回在 dwPageSize 参数。)但是,最重要的是,整个内存块跨越 0x10000 字节(或 64K 在大多数情况下)从 pAddress 将不会 可用于任何进一步的分配。因此从某种意义上说,通过分配 8 个字节,您也可以要求 65536 个字节。

所以这个故事的寓意是不要替代 VirtualAlloc 用于应用程序中的通用内存分配。它必须用于非常特殊的情况,就像使用 以下。(通常用于保留/分配大内存块。)

使用 VirtualAlloc 错误地可能会导致严重的内存碎片。

堆创建 / 堆分配 / 堆自由 / 堆销毁

简而言之, 函数基本上是一个包装器 VirtualAlloc 功能。这里的其他答案提供了一个很好的概念。我要补充一点,从一个非常简单的角度来看, 作品是这样的:

  • HeapCreate 通过调用保留一大块虚拟内存 VirtualAlloc 内部(或 ZwAllocateVirtualMemory 再具体一点)。它还建立了一个内部数据结构,可以跟踪虚拟内存保留块内更小的大小分配。

  • 任何致电 HeapAllocHeapFree 实际上并不分配/释放任何新内存(当然,除非请求超出了已保留的内存) HeapCreate)但相反,他们 米出 (或者 commit)先前保留的大块,通过将其分割成用户请求的更小的内存块。

  • HeapDestroy 依次调用 VirtualFree 这实际上释放了虚拟内存。

所以这一切都使得 函数是应用程序中通用内存分配的完美候选者。它非常适合任意大小的内存分配。但为了方便,需要付出很小的代价 函数的缺点是它们引入了轻微的开销 VirtualAlloc 当保留更大的内存块时。

另一件好事是关于 是你真的不需要创建一个。它通常是在您的流程开始时为您创建的。所以人们可以通过调用来访问它 获取进程堆 功能。

分配内存 / 自由的

是特定于语言的包装器 功能。不像 HeapAlloc, HeapFree, , ETC。这些函数不仅适用于 Windows 编译的代码,也适用于其他操作系统(例如 Linux 等)

如果您使用 C 语言编程,这是分配/释放内存的推荐方法。(除非您正在编写特定的内核模式设备驱动程序。)

新的 / 删除

来作为 高水平 (嗯,对于 C++) 内存管理运算符。它们专门针对 C++ 语言等 malloc 为了 C, ,也是包装 heap 功能。他们还有一大堆自己的代码来处理 C++- 构造函数的特定初始化、析构函数中的释放、引发异常等。

如果您进行编程,这些函数是分配/释放内存和对象的推荐方法 C++.


最后,我想对其他回复中有关使用的内容发表评论 VirtualAlloc 在进程之间共享内存。 VirtualAlloc 其本身不允许与其他进程共享其保留/分配的内存。为此,需要使用 CreateFileMapping 可以创建可与其他进程共享的命名虚拟内存块的 API。它还可以将磁盘上的文件映射到虚拟内存中以进行读/写访问。但这是另一个话题了。

概要:

  • VirtualAlloc、HeapAlloc 等是直接从操作系统分配各种类型内存的 Windows API。VirtualAlloc 管理 Windows 虚拟内存系统中的页面,而 HeapAlloc 从特定操作系统堆进行分配。坦率地说,您不太可能需要使用它们中的任何一个。

  • malloc 是一个标准 C(和 C++)库函数,用于为进程分配内存。malloc 的实现通常会在应用程序启动时使用操作系统 API 之一创建内存池,然后在发出 malloc 请求时从中进行分配

  • new 是一个标准 C++ 运算符,它分配内存,然后在该内存上适当地调用构造函数。它可以根据 malloc 或操作系统 API 来实现,在这种情况下,它通常也会在应用程序启动时创建内存池。

VirtualAlloc ===> UNIX下sbrk()

HeapAlloc ====> UNIX下malloc()

VirtualAlloc =>直中分配到虚拟内存,则预留/提交块。这非常适合大的分配,例如大的阵列。

HeapAlloc / new =>分配上的默认堆(或者您可以创建任何其他堆)的存储器。这种分配每个对象,是伟大的小物件。默认堆因此,序列化有保证线程分配(这可能会导致对高性能情景的一些问题,这就是为什么你可以创建自己的堆)。

malloc =>使用C运行时堆,类似于HeapAlloc但它是常见的兼容性的情况。

概括地说,该堆仅仅是一个,其由堆管理器(而不是原始虚拟存储器)支配虚拟内存块

在存储世界上最后一个模型是内存映射文件,这个场景是伟大的大块数据(如大文件)。这是在内部使用时打开一个EXE(它不会加载EXE在存储器中,只是创建一个存储器映射文件)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top