Win内存分配函数(GlobalAlloc/HeapAlloc/LocalAlloc/VirtualAlloc)
Win内存分配函数(GlobalAlloc/HeapAlloc/LocalAlloc/VirtualAlloc)
来源:http://blog.csdn.net/chunyexiyu/article/details/39320805
内存分配函数/内存管理API
参考:
Windows MSDN
http://msdn.microsoft.com/en-us/library/aa908768.aspx
附助资料:
http://blog.csdn.net/susubuhui/article/details/7315094
http://wenku.baidu.com/link?url=yxgCWePPV1kFaIUciEspYgm34wNAnMLDoduBlfsEEo-mW0JFRVEOkixomUjPatqw_jOXZcqQ1CLoeBSZqLuse1KiyHD6ysZTMIzLy_sPgPS
http://blog.csdn.net/sharecode/article/details/7464915
Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu 转载请标明来源
对于Windows来说,提供了一些API接口进行Heap内存管理,是独立于C++/C程序之外的,仅用于Windows平台的API。
大概分为下面几组接口:
老的Heap接口GlobalXXX(新程序不建议使用,这些函数存在主要是兼容以前写的程序):
GlobalAlloc/GlobalRelloc/GlobalFree:从Heap申请一块内存
GlobalLock/GlobalUnlock: 从GlobalAlloc的内存中申请一段内存
函数参数:
新的Heap接口HeapXXX:
HeapCreate/HeapDestroy/GetProcessHeap:从Heap中申请一块内存
HeapAlloc/HeapRelloc/HeapFree/HeapSize:从HeapCreate的内存中申请一段内存
HeapValidatee:查询Heap或Alloc的信息
当前进程Heap内存接口LocalXXX:
LocalAlloc/LocalReAlloc/LocalFree/LocalSize:从当前Heap的内存中申请一段内存,相当于从HeapAlloc从GetProcessHeap中申请内存。
虚拟地址内存接口: VirtualXXX
VirtualAlloc/VirtualFree/ VirtualProtect/VirtualQuery:从进程堆中申请页面内存数据。通常用于申请一段大内存,最少申请一页。reserves or commits a region of pages。
关于这一块详细请参考:http://blog.csdn.net/sharecode/article/details/7464915
malloc,new,VirtualAlloc,HeapAlloc这几组的执行效率:
参考:http://blog.csdn.net/susubuhui/article/details/7315094
分配大内存的时候 VirtualAlloc才能体现出优势,申请小内存时比较慢。
至于小块内存那就是HeapAlloc > malloc > new,因为都是调用HeapAlloc,直接使用HeapAlloc要快很多。
扩展的新接口xxxEx(不是所有版本都支持)
以Ex结尾,例如VitualAllocEx,可以指定process handle,从而从其它运行进程空间申请一段内存。
函数说明:
HeapCreate:
从内存区申请一段内存作为堆。This function reserves memory from the shared memory area.
HeapDestroy:
删除HeapCreate创建的堆。This function destroys the specified heap object.
GetProcessHeap:
获取当前进程的堆Handle。注意这个不能使用Destroy删除。This function obtains a handle to the heap of the calling process. This handle can then be used in calls to the HeapAlloc,HeapReAlloc,HeapFree, andHeapSize functions.
HeapAlloc:
从指定堆申请一段内存,该段内存是不被移动的。This function allocates a block of memory from a heap. The allocated memory is not movable.
HeapReAlloc:
从指定堆重新申请一段内存。This function reallocates a block of memory from a heap. The allocated memory is not movable.
HeapFree:
释入HeapAlloc或HeapReAlloc申请的内存。This function frees a memory block from a heap. The memory block was allocated by the HeapAlloc or theHeapReAllocfunction.
HeapSize:
根据Handle、内存开始地址,查询一段HeapAlloc内存的大小。This function returns the size, in bytes, of a memory block allocated from a heap by the HeapAllocorHeapReAlloc function.
HeapValidate:
检查Heap Handle或Heap Handle下申请的内存是否有效。
This function validates the specified heap. HeapValidate scans all the memory blocks in the heap and verifies that the heap control structures maintained by the heap manager are in a consistent state. The HeapValidate function can also be used to validate a single memory block within a specified heap without checking the validity of the entire heap.
LocalAlloc/LocalReAlloc/LocalFree/LocalSize:
从当前进程Heap中进行操作。该组函数相当于HeapXXX指定Heap Handle为当前进程Handle。函数参考HeapAlloc / HeapReAlloc/ HeapFree/ HeapSize作用。
LocalAlloc : This function allocates the specified number of bytes from the heap.
In the linear Windows Embedded CE API environment, there is no difference between the local heap and the global heap.LocalAlloc is equivalent toHeapAlloc(GetProcessHeap, …).
VirtualAlloc/VirtualFree/ VirtualProtect/VirtualQuery:
从当前进程空间中申请页面空间数据,最少申请一页。
The VirtualAlloc function reserves or commits a region of pages in the virtual address space of the calling process. Memory allocated by this function is automatically initialized to zero, unless MEM_RESET is specified.
To allocate memory in the address space of another process, use theVirtualAllocEx function.
关于内存的5个函数(malloc,VirtualAlloc,GlobalAlloc,LocalAlloc,HeapAlloc)
来源:http://www.cnblogs.com/Madridspark/p/5778433.html
VirtualAlloc
该函数的功能是在调用进程的虚地址空间,预定或者提交一部分页,如果用于内存分配的话,并且分配类型未指定MEM_RESET,则系统将自动设置为0
一次分配 1PAGE 以上的 RAM. 每次分配都是 PAGE 的整数倍. 你不会想为了分配 1 个 BYTE 的空间而浪费剩下的 4095 字节. OK, 你可以自己写算法, 多分配几 PAGE. 然后每次分配少量数据时就从那几 PAGE 中划分出来. KERNEL32 提供了一个解决办法, 用 HeapAlloc/GlobalAlloc 分配 RAM. 这样, KERNEL32 帮助完成分配动作, 并且尽量在减少用于跟踪空闲区域和已占用区域消耗的数据结构.
GlobalAlloc 和 LocalAlloc
从全局堆中分配出内存供程序使用
都是 Windows 系统提供的内存分配函数, 他们的区别在于 16BIT 代码时代, 那时没有不同的进程内存空间, GlobalAlloc 是在全局的, 公用的远堆上分配; LocalAlloc 则在任务自己的近堆上分配. 在 Win32 平台下这两个函数是完全相同的, 都是在进程自己的内存空间中分配, Lock 之后的结果是普通指针(32位近指针).
HeapAlloc
从堆上分配一块内存,且分配的内存是不可移动的(即如果没有连续的空间能满足分配的大小,程序不能将其他零散的空间利用起来,从而导致分配失败),该分配方法是从一指定地址开始分配,而不像GloabalAlloc是从全局堆上分配,这个有可能是全局,也有可能是局部。
HeapCreate 就已经完成了创建堆的操作. HeapAlloc, HeapReAlloc 和 HeapFree 都是从这个堆中分配, 释放内存的函数. 也就是说, Windows 系统其实已经为我们提供了完整的一套使用自己的局部堆的操作, 不过没有看到指定分配策略的方法. 根据编译器提供的源代码来 看, VC 中的 malloc, realloc 和 free 等函数主要功能就是用这几个 API 函数来实现的, 而 BC 中的实现相当复杂, 似乎是维护了一套自己的逻辑. 据说 BC 的内存分配比 VC 快, 大概是这个原因.
很久以前也有个产品叫做 WINDOWS. 那时候的 WINDOWS 是 16BIT 的, 地址空间有些紧俏, 有钱不够, 还需要粮票肉票才能拿到. 你已经调用 GlobalAlloc 和已经出钱的性质一样. GlobalAlloc 还不够, 有时候需要 GlocalLock 才能确定你的东西确实可以拿到手, 不然你的指针会非法, 被充公, 你的应用会被杀头. 扯远了. 后来 OS 进化了, 觉得可以取消粮票肉票, 但是你必须用新版钞票才行. 那就是 HeapAlloc. 只要市场上的 RAM 数量没问题, 你的 HeapAlloc 没问题, 那就总能拿到东西. 但是, 你总不能说有了 2000 版的钞票, 那 80 版的马上作废啊, 那 GlobalAlloc 也只好继续流通下去. 至于可以流通到什么时候, 没人知道. // 这比喻相当经典啊!!!
new 与它们的区别未免太大, 因为与 C++ 的构造函数和异常机制有关. 一般编译器中的 new 都是用 malloc 来分配内存的. 用 malloc 与其它两个函数比较应该更合理. 一般 malloc 的实现并不是从系统的堆中分配的, 而是从编译器连接的运行库自己管理的堆中, 在 Win32 平台上的开发工具的编译结果中, 通常是用 HeapCreate 创建一个堆, 用 HeapAlloc 和 HeapRealloc 维护堆的空间增长, 在最后用 HeapDestroy 删除堆. 而在用 malloc 分配, 用 free 释放时则由运行库的代码负责从这个堆中分配空间和向这个堆中归还空间, 并维护这个堆中的数据结构. 由于 malloc 堆的管理是由运行库自己管理的, 所在当我们使用静态运行库时, 如果在一个 DLL 中用 malloc 分配了内存而在另一个 DLL 中用 free 去释放它, 通常都会产生问题. 这是因为每个DLL都连接了一份运行库的代码, 从而也都有一个自己的局部堆, 而在用 free 释放时它会假设这块内存是在自己的堆中分配的, 从而导致错误. 而通过 GlobalAlloc 和 LocalAlloc 分配的内存不存在这个问题.
HeapAlloc、VirtualAlloc、GlobalAlloc和LocalAlloc
来源:http://blog.chinaunix.net/uid-26111972-id-2239571.html
1. HeapAlloc:
LPVOID
HeapAlloc(
HANDLE hHeap,
DWORD dwFlags,
SIZE_T dwBytes
);
hHeap是进程堆内存开始位置。
dwFlags是分配堆内存的标志。包括HEAP_ZERO_MEMORY,即使分配的空间清零。
dwBytes是分配堆内存的大小。
其对应的释放空间函数为HeapFree。
2. GlobalAlloc:该函数用于从全局堆中分配出内存供程序使用,函数原型为:
HGLOBAL GlobalAlloc(
UINT uFlags,
SIZE_T dwBytes
);
uFlags参数含义
GHND GMEM_MOVEABLE和GMEM_ZEROINIT的组合
GMEM_FIXED 分配固定内存,返回值是一个指针
GMEM_MOVEABLE 分配活动内存,在Win32中,内存块不能在物理内存中移动,但能在默认的堆中移动。返回值是内存对象的句柄,用函数GlobalLock可将句柄转化为指针
GMEM_ZEROINIT 将内存内容初始化为零
GPTR GMEM_FIXED和GMEM_ZEROINIT的组合
一般情况下我们在编程的时候,给应用程序分配的内存都是可以移动的或者是可以丢弃的,这样能使有限的内存资源充分利用,所以,在某一个时候我们分配的那块内存的地址是不确定的,因为他是可以移动的,所以得先锁定那块内存块,这儿应用程序需要调用API函数GlobalLock函数来锁定句柄。如下: lpMem=GlobalLock(hMem); 这样应用程序才能存取这块内存。所以我们在使用GlobalAllock时,通常搭配使用GlobalLock,当然在不使用内存时,一定记得使用 GlobalUnlock,否则被锁定的内存块一直不能被其他变量使用。
GlobalAlloc对应的释放空间的函数为GlobalFree。
3. LocalAlloc:该函数用于从局部堆中分配内存供程序使用,函数原型为:
HLOCAL LocalAlloc(
UINT uFlags,
SIZE_T uBytes
);
参数同GlobalAlloc。
在 16位Windows中LocalAlloc和GlobalAlloc是有区别的,因为在16位windows用一个全局堆和局部堆来管理内存,每一个应用程序或dll装入内存时,代码段被装入全局堆,而系统又为每个实例从全局堆中分配了一个64kb的数据段作为该实例的局部堆,用来存放应用程序的堆栈和所有全局或静态变量。而 LocalAlloc/GlobalAlloc就是分别用于在局部堆或全局堆中分配内存。
而在全局堆中分配的内存是为各个进程共享的,每个进程只要拥有这个内存块的句柄都可以访问这块内存,但是每个全局内存空间需要额外的内存开销,造成分配浪费。而且一旦发生严重错误,可能会影响到整个系统的稳定。
不过在Win32中,每个进程都只拥有一个省缺的私有堆,它只能被当前进程访问。应用程序也不可能直接访问系统内存。所以在Win32中全局堆和局部堆都指向进程的省缺堆。用LocalAlloc/GlobalAlloc分配内存没有任何区别。甚至LocalAlloc分配的内存可以被 GlobalFree释放掉。所以在Win32下编程,无需注意Local和Global的区别,一般的内存分配都等效于 HeapAlloc(GetProcessHeap(),...)。
LocalAlloc对应的释放函数为LockFree。
4. VirtualAlloc:该函数的功能是在调用进程的虚地址空间,预定或者提交一部分页,如果用于内存分配的话,并且分配类型未指定MEM_RESET,则系统将自动设置为0;其函数原型:
LPVOID VirtualAlloc(
LPVOID lpAddress, // region to reserve or commit
SIZE_T dwSize, // size of region
DWORD flAllocationType, // type of allocation
DWORD flProtect // type of access protection
);
VirtualAlloc 可以通过并行多次调用提交一个区域的部分或全部来保留一个大的内存区域。多重调用提交同一块区域不会引起失败。这使得一个应用程序保留内存后可以随意提交将被写的页。当这种方式不在有效的时候,它会释放应用程序通过检测被保留页的状态看它是否在提交调用之前已经被提交。
VirtualAlloc对应的释放函数为VirtualFree。
5.Malloc:malloc 与free是C++/C语言的标准库函数,可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用 malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
6.New:new/delete 是C++的运算符。可用于申请动态内存和释放内存。C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。C++程序经常要调用C函数,而C程序只能用malloc /free管理动态内存。new 是个操作符,和什么"+","-","="...有一样的地位.
malloc是个分配内存的函数,供你调用的.
new是保留字,不需要头文件支持.
malloc需要头文件库函数支持.new 建立的是一个对象,
malloc分配的是一块内存.
new建立的对象你可以把它当成一个普通的对象,用成员函数访问,不要直接访问它的地址空间
malloc分配的是一块内存区域,就用指针访问好了,而且还可以在里面移动指针.
内存泄漏对于malloc或者new都可以检查出来的,区别在于new可以指明是那个文件的那一行,而malloc没有这些信息。new可以认为是malloc加构造函数的执行。new出来的指针是直接带类型信息的。而malloc返回的都是void指针。