我们以前最常用的方法。用于分配较小的数据块:链表和树。无分配粒度和页面边界的问题。
缺点:速度慢,无法直接控制物理存储器的提交和回收。
一、进程的默认堆栈:
n 进程初始化时,系统在进程的地址空间创建。默认大小1MB。可以用/HEAP链接开关改变默认大小(DLL没有与其相关的堆栈!): /HEAP: reserve[,commit]
n 老的16位函数LocalAlloc,GlobalAlloc都是从默认堆栈中分配内存。
n 获取进程默认堆栈句柄:HANDLE GetProcessHeap();
二、为什么要创建辅助堆栈:
1. 保护组件
2. 更加有效的内存管理
3. 进行本地访问
4. 减少线程同步开销
5. 迅速释放
三、如何创建辅助堆栈:
HANDLE HeapCreate(
DWORD fdwOptions,//0、HEAP _GENERATE_EXCEPTIONS、~_NO_SERIALIZE
SIZE_T dwInitialSize, // 最初提交的字节数
SIZE_T dwMaximumSize); // 最大值,=0:可扩展到物理存储器用完为止。
n HEAP_NO_SERIALIZE标志建议不用(但如果是单线程程序、或 只有单个线程访问该堆栈 或 使用互斥机制 则能安全使用)。如果不用该标志,调用堆栈函数的线程运行速度降低!
n HEAP _GENERATE_EXCEPTIONS:如果内存分配出错时,会得到系统通知。
四、从堆栈中分配内存块:
PVOID HeapAlloc(
HANDLE hHeap, // 堆栈句柄
DWORD fdwFlags, // 影响分配的标志
SIZE_T dwBytes); // 字节数
fdwFlags:
n HEAP_ZERO_MEMORY:初始化为0;
n HEAP_GENERATE_EXCEPTIONS:如果内存不足,引发异常(STATUS_NO_MEMORY:内存不足, STATUS_ACCESS_VIOLATION:堆栈被破坏或参数错误);如果在HeapCreate使用了该标志,则不需要再设定;如果不设定该标志,HeapAlloc失败返回NULL。
n HEAP_NO_SERIALIZE:同上。
如果分配较大的内存块(1MB +-),最好用VirtualAlloc!
五、改变内存块大小:
PVOID HeapReAlloc(
HANDLE hHeap,
DWORD fdwFlags, // HEAP_REALLOC_IN_PLACE_ONLY:不移动位置,链表或树有必要用该标志,其他同上
PVOID pvMem, // 原地址
SIZE_T dwBytes); // 字节数
六、查询内存块大小:
SIZE_T HeapSize(
HANDLE hHeap,
DWORD fdwFlags, // =0 或 HEAP_NO_SERIALIZE
LPCVOID pvMem); // 地址
七、释放内存块(可能回收物理存储器):
BOOL HeapFree(
HANDLE hHeap,
DWORD fdwFlags, // =0或 HEAP_NO_SERIALIZE
PVOID pvMem);
八、撤销堆栈(回收物理存储器):
BOOL HeapDestroy(HANDLE hHeap);
九、C++堆栈操作函数:new,delete(在你的类中重载这两个操作符,在内部使用堆栈操作函数)
十、其他函数:
n 在WIN98, 2000中均适用的函数:Heap32First, Heap32Next, Heap32ListFirst, Heap32ListNext.
n 仅仅用于WIN2000的函数:
1. 查询线程中堆栈句柄:
DWORD GetProcessHeaps(DWORD dwNumHeaps, PHANDLE pHeaps);
使用前,先分配一个HANDLE数组。
2. 测试堆栈的完整性:
BOOL HeapValidate(HANDLE hHeap, //
DWROD fdwFlags,
LPCVOID pvMem);
如果hHeap = 0,在pvMem = NULL时,该函数遍历检查堆栈中的内存块;pvMem = 特定地址时,他只测试这个地址的内存块。
3. 合并地址中的空闲内存块并回收不包含已经分配的地址内存块的存储器页面:
UINT HeapCompact(
HANDLE hHeap,
DWORD fdwFlags); // =0 或HEAP_NO_SERIALIZE
4. 线程同步的函数:
u BOOL HeapLock(HANDLE hHeap);
u BOOL HeapUnlock(HANDLE hHeap);
但,事实上,HeapAlloc, HeapSize, HeapFree等函数在内部调用这两个函数。自己很少调用这两个函数。
5. BOOL HeapWalk(HANDLE hHeap, PPROCESS_HEAP_ENTRY pHeapEntry);用于调试,他使你能遍历堆栈的内容。使用前PROCESS_HEAP_ENTRY结构成员lpData=NULL初始化,返回TRUE可以查看结构成员。若要进入堆栈中下一内存块,再次调用该函数,pHeapEntry 为上次使用的地址。返回FLASE时,标识堆栈中已没有其它内存块了。(需要使用线程同步函数!)