在《Windows核心编程》第五版的第十八章 《堆》 中提到了进程默认堆和额外创建的堆。这在编程中是十分重要的知识,今天整理一下。
1,堆非常适合分配大量的小型数据。使用堆可以让程序员专心解决手头的问题,而不必理会分配粒度和页面边界之类的事情。因此堆是管理链表和数的最佳方式。但是堆进行内存分配和释放时的速度比其他方式都慢,而且无法对物理存储器的调拨和撤销调拨进行控制。
为了能适应各种硬件平台,如果程序员想要控制物理存储器的调拨和撤销调拨,就不应该使用堆,而应该使用虚拟内存(VirtualAlloc和VirtualFree)。
2.进程默认堆。
进程初始化时,系统会在进程的地址空间中创建一个堆。这个堆被称为进程的默认堆。默认情况下,这个堆的地址空间区域大小是1MB。程序员可以控制这个大小。我们可以在创建应用程序时用/HEAP连接器开关来改变默认堆的大小。由于DLL没有与之关联的堆,因此在创建DLL时,不应该使用/HEAP开关。
我们可以通过调用GetProcessHeap来得到进程默认堆
3.为什么要创建额外的堆?
HANDLE HeapCreate(
DWORD fdwOptions,
SIZE_T dwInitilialize,
SIZE_T dwMaximumSize);
5.堆创建后,需要从堆中分配内存时,要调用HeapAlloc函数:
PVOID HeapAlloc(
HANDLE hHeap,
DWORD fdwFlags,
SIZE_T dwBytes);
如果分配成功HeapAlloc会返回内存块地址。否则将会返回NULL。
默认情况下,对堆的访问会依次进行。当任何程序试图从堆中分配一块内存时,HeapAlloc会执行以下操作:
1:遍历已分配的内存的链表和闲置内存的链表。
2:找到一块足够大的闲置内存块。
3:分配一块新的内存,将2找到的内存块标记为已分配。
4:将新分配的内存块添加到已分配的链表中。
注意:在分配大于1MB的内存时应该避免使用堆函数,而应该使用VirtualAlloc函数。
6.调整内存块大小
PVOID HeapReAlloc(
HANDLE hHeap,
DWORD fdwFlags,
PVOID pvMem,
SIZE_T dwBytes);
7.获得内存块大小
SIZE_T HeapSize(
HANDLE hHeap,
DWORD fdwFlags,
LPCVOID pvMem);
8.释放内存块
BOOL HeapFree(
HANDLE hHeap,
DWORD fdwFlags,
PVOID pvMem);
9.销毁堆
BOOL HeapDestroy(HANDLE hHeap);
10.其他
函数GetProcessHeaps返回一个HANDLE数组 可获得包括默认堆在内的所有堆的句柄
一下两个函数要配对使用,用于线程同步:
BOOL HeapLock(HANDLE hHeap);
BOOL HeapUnlock(HANDLE hHeap);
让堆中闲置的内存块能重新结合在一起,并撤销调拨给堆中闲置内存块的存储器,可以调用HeapCompact:
UINT HeapCompact(
HANDLE hHeap,
DWORD fdwFlags);
HeapValidate可以验证堆的完整性。
BOOL HeapValidate(
HANDLE hHeap,
DWORD fdwFlags,
LPCVOID pvMem);