-堆
系统内部,堆就是一块预订的地址空间区域。刚开始,区域内的大部分页面没有调拨物理存储器。随着不断中堆中分配内存,堆管理器会给堆调拨越来越多的物理存储器。物理存储器从页交换文件中分配的。释放堆中内存块时,堆管理器会撤销已调拨的物理存储器。
-进程的默认堆
1.进程初始化时,系统会在进程的地址空间中创建一个堆。称为进程的默认堆。默认的地址空间区域大小1MB。
创建应用时,可用/HEAP改变默认大小。
/HEAP:reserve[, commit]
2.许多windows函数用到了进程的默认堆,且应用有许多线程同时调用各种windows函数。故,对默认堆的访问须依次进行。
系统保证,一次只让一个线程从默认堆分配或释放内存块。
-堆
一个进程可有多个堆。
默认堆是在进程开始运行前由系统自动创建的,在进程终止后自动销毁。
每个堆都有一个用来标识自己的堆句柄,所有分配和释放内存块的堆函数都会在参数中用到这个堆句柄。
// 得到进程默认堆的句柄
HANDLE GetProcessHeap();
-自定义堆
1.创建
// 预订地址空间+调拨区域内一小块
HANDLE WINAPI HeapCreate(
// HEAP_NO_SERIALIZE 取消堆多线程保护,由开发人员自行实现多线程保护机制
// HEAP_GENERATE_EXCEPTIONS 在堆中分配内存失败时,抛出异常
// HEAP_CREATE_ENABLE_EXECUTE 在堆中存放可执行代码
// 0无特殊要求,传0
_In_ DWORD flOptions,
// 初始调拨块大小
_In_ SIZE_T dwInitialSize,
// > 0,预订区域大小
// 区域可变。
_In_ SIZE_T dwMaximumSize
);
自定义堆实现多线程保护支持
BOOL WINAPI HeapLock(
_In_ HANDLE hHeap
);
BOOL WINAPI HeapUnlock(
_In_ HANDLE hHeap
);
未指定HEAP_NO_SERIALIZE 标志,对堆的访问会依次进行,使多线程从同一个堆分配和释放内存块,也不会存在堆数据被破坏。
2.从堆中分配内存
LPVOID WINAPI HeapAlloc(
_In_ HANDLE hHeap,
// HEAP_GENERATE_EXCEPTIONS 如果要求的大小太大了或其他原因导致操作失败,触发异常
// HEAP_NO_SERIALIZE 本次操作不需要多线程下互斥保护
// HEAP_ZERO_MEMORY 堆中本次调拨内存初始值为0
_In_ DWORD dwFlags,
// 要求从堆中分配的字节数
_In_ SIZE_T dwBytes
)
BOOL WINAPI HeapFree(
_In_ HANDLE hHeap,
// 0
// HEAP_NO_SERIALIZE 本次操作不需要多线程下互斥保护
_In_ DWORD dwFlags,
_In_ LPVOID lpMem
);
LPVOID WINAPI HeapReAlloc(
_In_ HANDLE hHeap,
// HEAP_GENERATE_EXCEPTIONS 如果要求的大小太大了或其他原因导致操作失败,触发异常
// HEAP_NO_SERIALIZE 本次操作不需要多线程下互斥保护
// HEAP_REALLOC_IN_PLACE_ONLY 新调拨块必须续着原有块
// HEAP_ZERO_MEMORY
新块中超出原始块部分内容为0
_In_ DWORD dwFlags,
// 指向原始块
_In_ LPVOID lpMem,
// 新的大小
_In_ SIZE_T dwBytes
);
3.获得堆内块大小
SIZE_T WINAPI HeapSize(
_In_ HANDLE hHeap,
// 0
// HEAP_NO_SERIALIZE
_In_ DWORD dwFlags,
_In_ LPCVOID lpMem
);
4.销毁
BOOL WINAPI HeapDestroy(
// 撤销区域内所有已调拨操作+撤销预订的区域
_In_ HANDLE hHeap
);
进程的默认堆由进程终止前自动销毁,不允许通过HeapDestroy销毁。
5.其它堆函数
DWORD WINAPI GetProcessHeaps(
_In_ DWORD NumberOfHeaps,
_Out_ PHANDLE ProcessHeaps
);
// 验证堆未被破坏
BOOL WINAPI HeapValidate(
_In_ HANDLE hHeap,
// HEAP_NO_SERIALIZE 没有多线程互斥
_In_ DWORD dwFlags,
// NULL验证整个堆
// 非NULL,验证堆内此块
_In_opt_ LPCVOID lpMem
);
// 返回最大可用堆内块大小
SIZE_T WINAPI HeapCompact(
_In_ HANDLE hHeap,
_In_ DWORD dwFlags
);
// 多线程保护堆,在堆访问函数内部调用此两个函数
// 锁定堆,堆被锁定,进程内其它线程不可用
BOOL WINAPI HeapLock(
_In_ HANDLE hHeap
);
// 解除锁定
BOOL WINAPI HeapUnlock(
_In_ HANDLE hHeap
);
// 枚举堆内的块
// 初始:lpEntry的lpData为NULL,每枚举成功一次,返回NULL。lpEntry被填充枚举的块信息。继续用此lpEntry执行调用,接着被填充下一块信息。枚举结束返回FALSE。
// 枚举开始,一般用HeapLock锁定堆。
// 枚举结束,一般用HeapUnlock解除锁定。
BOOL WINAPI HeapWalk(
_In_ HANDLE hHeap,
_Inout_ LPPROCESS_HEAP_ENTRY lpEntry
);