堆 是一种对内存进行操控的方法之一。 他非常适合分配大量的小型数据。 他是用来管理链表和树的最佳方式。 优点:能让我们专心解决手头的问题,不必理会分配粒度和页面边界。 缺点:分配和释放内存块的速度比其他方式慢,也无法再对物理存储器的调拨和撤销调拨进行直接控制。 |
HANDLE WINAPI HeapCreate(
__in DWORD flOptions,
__in SIZE_T dwInitialSize,
__in SIZE_T dwMaximumSize );
BOOL WINAPI HeapDestroy( __in HANDLE hHeap );
LPVOID WINAPI HeapAlloc(
__in HANDLE hHeap,
__in DWORD dwFlags,
__in SIZE_T dwBytes );
BOOL WINAPI HeapFree(
__in HANDLE hHeap,
__in DWORD dwFlags,
__in LPVOID lpMem );
LPVOID WINAPI HeapReAlloc(
__in HANDLE hHeap,
__in DWORD dwFlags,
__in LPVOID lpMem,
__in SIZE_T dwBytes );
SIZE_T WINAPI HeapSize(
__in HANDLE hHeap,
__in DWORD dwFlags,
__in LPCVOID lpMem );
大家都知道这两个操作符是可以重载的,如果我们不重载那么编译器会自动生成代码来供我们调用。
下面我们就自己来建立一个类:
class HeapC{
public:
void* operator new(size_t size);
void operator delete(void* p);
private:
static HANDLE s_hHeap;
static UINT s_num;
};
在类中我们重载了这两个操作符,我的目的是让他们来利用堆。
可以看到私有的两个变量是静态变量,这样HeapC的所有对实例就都能共享这两个变量了。
其中s_hHeap 是句柄, s_num 是计数器。
下面我么来看一下这两个操作符重载的实现。
HANDLE HeapC::s_hHeap = NULL;
UINT HeapC::s_num = 0;
void* HeapC::operator new(size_t size)
{
if(s_hHeap == NULL)
{
s_hHeap = HeapCreate(HEAP_NO_SERIALIZE, 0, 0);//这个实例不涉及多线程
if(s_hHeap == NULL)
return NULL;
}
void *p = HeapAlloc(s_hHeap, 0, size);
if(p != NULL)
s_num++;
return p;
}
void HeapC::operator delete(void* p)
{
if(HeapFree(s_hHeap, 0, p))
s_num--;
if(s_num == 0)
if(HeapDestroy(s_hHeap))
s_hHeap = NULL;
}
OK,我们先是判断是否创建了堆,没有的话我们就来创建一个堆,创建成功后我们就来分配内存, 如果两者都成功了,那么我们就要增加我们计数器的数值了。
如果存在堆了,我们就来分配内存,分配成功后就来增加计数器。
下面就是要销毁了,先来销毁分配了的内存,成功就减少计数器。
直到我们的计数器是0后,我们就可以来销毁堆了。
当然,我们还要考虑类的派生,内存碎片等问题。