一、 堆的概述
从内部来讲,堆时保留的地址空间的一个区域,保留区域中大多数页面没有被提交物理存储器,当从堆中分配越来越多的内存时,堆管理器把更多的物理存储器提交给堆。物理存储器总是从系统的页文件中分配的。
当进程初始化时,系统在进程地址空间中创建一个堆,该堆称为进程的默认堆,该队地址空间区域的大小未 1M ,许多系统函数需要使用一些临时内存块,这些内存块时从进程的默认堆中分配的。
默认堆的访问是顺序进行的,基同一时间指允许一个线程对堆进行访问,保证了堆访问的互斥与同步。
二、 自定义堆的必要性
除了进程的默认堆之外,可以在进程的地址空间中创建一些辅助堆,辅助堆的创建将有助于提高系统的性能。
1、 保护组件
在一个堆中存放两种类型的数据时,若其中一个出现错误,很可能影响到另一个结构,如一个链表和一个二叉树存放在同一个堆中,他们的结点交叉存放,假如在修改链表中的某个结点时,错误的修改了节点的下一个内存地址,又恰巧下一个节点存储的是二叉树的一个结点,那么链表的错误将影响到二叉树。
若将链表和二叉树存放在不同的堆中,将大大减少上述错误。
2、 更有效的利用内存
当不同大小的结点占据相同的堆时,由于堆存储的不连续性,很可能释放了许多不连续的小的内存块,但不能满足一个较大的内存块的申请,若一个堆中存放的是相同大小的内存块,那么释放的内存块马上能够在下一次申请时分配出去。从而提高了内存的利用率。
3、 有利于进行本地访问
将同一种类型的数据存放在一个堆中,他们更又可能分配到同一个页面上,从而提高了数据的局部性,减少缺页概率。
4、 减少线程同步的开销
当确定进程为单线程时,在创建堆时可以告诉系统,不需要进行互斥与同步保护,从而减少线程同步的开销。
5、 迅速释放堆
将专用堆用于某些数据结构后,就可以释放整个堆,而不必显示释放堆中的每个内存块。
三、 使用辅助堆
1、 创建辅助堆
HANDLE HepaCreate(
DWORD fdwOptions, /*如何在堆上执行各种操作*/
SIZE_T dwInitialSize, /*最初提交给堆的字节数*/
SIZE_T dwMaximumSize); /*堆的最大值,当值为0时表示能无限扩展*/
堆上执行的操作标识:
HEAP_NO_SERIALIZE:不进行同步
HEAP_GENERATE_EXCEPTIONS:当分配或重新分配堆中内存块失败时,引发异常
2、 从堆中分配内存
PVOID HeapAlloc(
HANDLE hHeap, /*堆句柄*/
DWORD fdwFlags, /*分配标识*/
SIZE_T dwBytes); /*从堆中分配的字节数*/
分配标识:
HEAP_ZERO_MEMORY:分配完毕后用0初始化
3、 改变内存块的大小
PVOID HeapReAlloc(
HANDLE hHeap, /*要改变其大小的堆*/
DWORD fdwFlags, /*创建标识*/
PVOID pvMem, /*要改变其大小的内存块的地址*/
SIZE_T dwBytes); /*内存块的新的大小*/
4、 查看内存块的大小
SIZE_T HeapSize(
HANDLE hHeap, /*堆句柄*/
DWORD fdwFlags, /*0或者HEAP_NO_SERIALIZE*/
LPCVOID pvMem); /*内存块地址*/
5、 释放内存块
BOOL HeapFree(
HANDLE hHead , /*堆句柄*/
DWORD fdwFlags, /*0或者HEAP_NO_SERIALIZE*/
PVOID pvMem); /*内存块地址*/
6、 撤销堆
BOOL HeapDestroy(
HANDLE hHeap); /*堆句柄*/
7、 获取默认堆句柄
HANDLE GetProcessHeap();
8、 获取进程中的所有堆
DWORD GetProcessHeaps(
DWORD dwNumHeaps, /*堆句柄数组大小*/
PHANDLE pHeaps); /*堆句柄数组*/
9、 检测堆的完整性
BOOL HeapVallidate(
HANDLE hHeap, /*堆句柄*/
DWORD fdwFlags, /*0或者HEAP_NO_SERIALIZE*/
LPCVOID pvMem); /*需要检测的内存块地址,当为NULL时检测堆中所有内存块*/
10、合并堆中空闲内存块
UINT HeapCompact(
HANDLE hHeap, /*堆句柄*/
DWORD fdwFlags); /*0或者HEAP_NO_SERIALIZE*/
11、堆的加锁与解锁
BOOL HeapLock(HANDLE hHeap); /*堆句柄*/
BOOL HeapUnlock(HANDLE hHeap); /*堆句柄*/
12、枚举堆中内存块
BOOL HeapWald(
HANDLE hHeap, /*堆句柄*/
PPROCESS_HEAP_ENTRY pHeapEntry);
堆的使用:
#pragma once
#include <iostream>
#include <windows.h>
using namespace std;
/*从自定义堆中申请空间的模版类*/
template <class T>
class LinkNode
{
public:
T node;
LinkNode * proNode;
LinkNode * nextNode;
static HANDLE heap;
static unsigned int numNode;
public :
void * operator new(size_t size);
void operator delete(void *p);
void * ChangeClassSize();
};
template <class T>
HANDLE LinkNode<T>::heap = NULL;
template <class T>
unsigned int LinkNode<T>::numNode = 0;
template<class T>
void *LinkNode<T>::operator new(size_t size)
{
if(heap == NULL)
{
/*创建自定义堆*/
heap = HeapCreate(0, 0, 0);
if(heap == NULL)
{
return NULL;
}
}
/*从堆中分配内存块*/
void * p = HeapAlloc(heap, 0, sizeof(LinkNode));
if(p != NULL)
{
++numNode;
}
return p;
}
template <class T>
void LinkNode<T>::operator delete(void *p)
{
/*释放堆中的内存块*/
if(HeapFree(heap, 0, p))
{
--numNode;
}
if(numNode == 0)
{
/*撤销自定义的堆*/
if(HeapDestroy(heap))
{
heap = NULL;
}
}
}
#include <iostream>
using namespace std;
#include "LinkNode.h"
void main()
{
LinkNode<int> *node = new LinkNode<int>();
node->node = 5;
cout << node->node << endl;
node->ChangeClassSize();
cout << node->node << endl;
system("pause");
}