当前位置:  开发笔记 > 运维 > 正文

VirtualAlloc和HeapAlloc之间有什么区别?

如何解决《VirtualAlloc和HeapAlloc之间有什么区别?》经验,为你挑选了4个好方法。

有很多方法在Windows环境中分配内存,如VirtualAlloc,HeapAlloc,malloc,new.

那么,它们之间的区别是什么?



1> Doug..:

每个API都用于不同的用途.每个人还要求在完成内存后使用正确的释放/释放功能.

的VirtualAlloc

一种低级Windows API,提供了许多选项,但主要用于相当特定情况下的用户.只能在(编辑:不是4KB)更大的块中分配内存.有些情况下你需要它,但你会知道你何时处于这些情况之一.最常见的一种情况是,您必须直接与另一个进程共享内存.不要将它用于通用内存分配.使用VirtualFree解除分配.

HeapAlloc

分配你要求的任何大小的内存,而不是大块VirtualAlloc.HeapAlloc知道什么时候需要打电话VirtualAlloc,并自动为你做.喜欢malloc,但仅限Windows,并提供了更多选项.适合分配一般内存块.某些Windows API可能要求您使用它来分配传递给它们的内存,或者使用它的随附数据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您可能被告知必须在特定情况下使用.


Doug:VirtualAlloc并不严格限制为4kb分配,它是GetSystemInfo(),SYSTEM_INFO :: dwAllocationGranularity返回的大小.它实际上是_RARELY_ 4kb.在我的主机上,它是64k,我怀疑你也一样.4KB是x86 ABI中各种discriptor表的最小页面大小条目.4KB是可以独立许可的最小尺寸,R/W/X,但它对VirtualAlloc没有任何意义.如果您参考VirtualAlloc文档,还有LARGE_PAGES选项(请参阅http://msdn.microsoft.com/en-us/library/aa366568(VS.85).aspx).
@ RandomNickName42:这不对.分配起始地址始终与粒度(64KB)对齐,但分配长度四舍五入到页面大小(4KB).实际上,地址空间以64KB块保留,但以4KB块的形式提交.起始地址的对齐通常不那么有趣,因此从大多数观点来看,VirtualAlloc可以在4KB块中运行.如果您尝试执行大量小型VirtualAlloc(您将耗尽地址空间)或某些花哨的东西(如相邻但单独的分配),这些细节将变得非常重要.

2> RandomNickNa..:

VirtualAlloc是OS虚拟内存(VM)系统的专门分配.VM系统中的分配必须以分配粒度(分配粒度)取决于体系结构.VM系统中的分配是最基本的内存分配形式之一.VM分配可以采用多种形式,内存不一定是专用的或物理上支持在RAM中(尽管可以).VM分配通常是一种特殊用途的分配类型,因为分配必须这样做

非常大,

需要分享,

必须根据特定值(性能原因)或

调用者不需要一次使用所有这些内存......

等等...

HeapAlloc基本上是什么malloc,new最终都呼吁.它被设计为在通用分配的许多不同类型的场景下非常快速和可用.这是经典意义上的"堆".堆实际上是由a设置的VirtualAlloc,这是用于最初从OS保留分配空间的内容.在初始化空间之后VirtualAlloc,配置各种表,列表和其他数据结构以维护和控制HEAP的操作.其中一些操作的形式是动态调整(增长和缩小)堆的大小,使堆适应特定的使用(某些大小的频繁分配)等.

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

其他一些常见的分配方法,如_alloca()_malloca()为主; FileMappings实际上是VirtualAlloc使用特定的位标志分配和设置的,这些位标志指定这些映射是类型的FILE.

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

***注意,完成的大内存分配HeapAlloc实际上是VirtualAlloc在一定大小之后发送的(几百k或16 MB或我遗忘的东西,但相当大:)).

***编辑我简要地谈到了IPC,并且VirtualAlloc还有一些非常简洁的相关VirtualAlloc内容,这个问题没有一个响应者讨论过.

VirtualAllocEx是一个进程可以用来在不同进程的地址空间中分配内存的东西.最典型的是,它通过CreateRemoteThread 组合使用以在另一个进程的上下文中进行远程执行(类似于,线程只在另一个进程中运行).CreateThread



3> ahmd0..:

如果您计划使用需要内存管理的语言(如C或C++),了解内存分配API(在Windows中)之间的区别非常重要.最好的方式来说明它恕我直言:

在此输入图像描述

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

理解这个图的方法是图表中的内存分配方法越高,它使用的是更高级别的实现.但是,让我们从底部开始.

内核模式内存管理器

它提供了操作系统的所有内存预留和分配,以及对内存映射文件,共享内存,写时复制操作等的支持.它不能直接从用户模式代码访问,所以我将跳过在这里.

VirtualAlloc/VirtualFree

这些是用户模式中可用的最低级 API .该函数基本上调用ZwAllocateVirtualMemory,而ZwAllocateVirtualMemory又执行快速系统调用以将进一步处理转移到内核内存管理器.它也是在用户模式下从所有可用内存中保留/分配新内存块的最快方法.VirtualAllocring0

但它有两个主要条件:

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

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

那么这个系统的粒度是多少?您可以通过调用GetSystemInfo来获取它.它作为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不当可能导致严重的内存碎片.

HeapCreate/HeapAlloc/HeapFree/HeapDestroy

简而言之,函数基本上是VirtualAlloc函数的包装器.这里的其他答案提供了一个非常好的概念.我将补充说,在一个非常简单的视图中,堆的工作方式是这样的:

HeapCreate通过VirtualAlloc内部调用(或ZwAllocateVirtualMemory具体)来保留大块虚拟内存.它还设置了一个内部数据结构,可以在保留的虚拟内存块中跟踪更小的大小分配.

任何调用HeapAllocHeapFree不实际分配/释放任何新内存(当然,除非请求超出已经保留的内容HeapCreate),而是通过将其解析为较小的内存块来计量(或commit)先前保留的大块.用户请求.

HeapDestroy反过来调用VirtualFree实际释放虚拟内存.

所以这一切使得函数成为应用程序中通用内存分配的理想选择.它适用于任意大小的内存分配.但是为了函数的便利而付出的代价是,它们VirtualAlloc在保留更大的内存块时会带来轻微的开销.

堆的另一个好处是你不需要创建.它通常是在您的流程开始时为您创建的.因此可以通过调用GetProcessHeap函数来访问它.

malloc /免费

函数的特定于语言的包装器.与等等不同HeapAlloc,HeapFree这些函数不仅适用于您的代码是针对Windows编译的,还适用于其他操作系统(例如Linux等)

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

新 /删除

作为一个高级(好吧C++)内存管理运营商.他们是为特定的C++语言,和喜欢mallocC,也是对的包装heap功能.它们还有一大堆自己的代码,用于处理C++构造函数的特定初始化,析构函数中的释放等.

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


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



4> 小智..:

概述:

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

malloc是一个标准C(和C++)库函数,它为您的进程分配内存.malloc的实现通常会使用其中一个OS API在您的应用启动时创建一个内存池,然后在您发出malloc请求时从中进行分配

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

推荐阅读
爱唱歌的郭少文_
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有