C++ 封裝私有堆(Private Heap)


  Private Heap 是 Windows 提供的一種內存內存機制,對於那些需要頻繁分配和釋放動態內存的應用程序來說,Private Heap 是提高應用程序性能的一大法寶,使用它能降低 new / malloc 的調用排隊競爭以及內存空洞。Private Heap 的原理及應用的資料很多,這里就不一一介紹了,常用的 Private Heap API 有以下幾個,具體介紹請參考幫助文檔:

HeapCreate();
HeapDestroy();
HeapAlloc();
HeapReAlloc();
HeapSize();
HeapFree();
HeapCompact();

  

  由於是 C 風格的 API,使用起來比較繁瑣,因此本座在閑暇之余用 C++ 對這些 API 進行了封裝,主要包括兩個類:

  • CPrivateHeap:自動創建和銷毀進程私有堆,每一個該類的對象都代表一個私有堆,所以該類對象的特點是: 一般生命周期都比較長,通常作為全局對象, 其他類的靜態成員對象或者一些長生命周期類對象的成員。
  • CPrivateHeapBuffer<T>:在私有堆中自動分配和釋放指定大小的內存,一般用於在函數體內分配和釋放局部作用域的堆內存,從而避免對 CPrivateHeap::Alloc() 和 CPrivateHeap::Free() 的調用。
#pragma once

class CPrivateHeap
{
public:
enum EnCreateOptions
{
CO_DEFAULT = 0,
CO_NO_SERIALIZE = HEAP_NO_SERIALIZE,
CO_GENERATE_EXCEPTIONS = HEAP_GENERATE_EXCEPTIONS,
CO_NOSERIALIZE_GENERATEEXCEPTIONS
= HEAP_NO_SERIALIZE |
HEAP_GENERATE_EXCEPTIONS
};

enum EnAllocOptions
{
AO_DEFAULT = 0,
AO_ZERO_MEMORY = HEAP_ZERO_MEMORY,
AO_NO_SERIALIZE = HEAP_NO_SERIALIZE,
AO_GENERATE_EXCEPTIONS = HEAP_GENERATE_EXCEPTIONS,
AO_ZEROMEMORY_NOSERIALIZE
= HEAP_ZERO_MEMORY |
HEAP_NO_SERIALIZE,
AO_ZEROMEMORY_GENERATEEXCEPTIONS
= HEAP_ZERO_MEMORY |
HEAP_GENERATE_EXCEPTIONS,
AO_NOSERIALIZE_GENERATESEXCEPTIONS
= HEAP_NO_SERIALIZE |
HEAP_GENERATE_EXCEPTIONS,
AO_ZEROMEMORY_NOSERIALIZE_GENERATESEXCEPTIONS
= HEAP_ZERO_MEMORY |
HEAP_NO_SERIALIZE |
HEAP_GENERATE_EXCEPTIONS
};

enum EnReAllocOptions
{
RAO_DEFAULT = 0,
RAO_ZERO_MEMORY = HEAP_ZERO_MEMORY,
RAO_NO_SERIALIZE = HEAP_NO_SERIALIZE,
RAO_GENERATE_EXCEPTIONS = HEAP_GENERATE_EXCEPTIONS,
RAO_REALLOC_IN_PLACE_ONLY = HEAP_REALLOC_IN_PLACE_ONLY,
RAO_ZEROMEMORY_NOSERIALIZE
= HEAP_ZERO_MEMORY |
HEAP_NO_SERIALIZE,
RAO_ZEROMEMORY_GENERATEEXCEPTIONS
= HEAP_ZERO_MEMORY |
HEAP_GENERATE_EXCEPTIONS,
RAO_ZEROMEMORY_REALLOCINPLACEONLY
= HEAP_ZERO_MEMORY |
HEAP_REALLOC_IN_PLACE_ONLY,
RAO_NOSERIALIZE_GENERATESEXCEPTIONS
= HEAP_NO_SERIALIZE |
HEAP_GENERATE_EXCEPTIONS,
RAO_NOSERIALIZE_REALLOCINPLACEONLY
= HEAP_NO_SERIALIZE |
HEAP_REALLOC_IN_PLACE_ONLY,
RAO_GENERATESEXCEPTIONS_REALLOCINPLACEONLY
= HEAP_GENERATE_EXCEPTIONS |
HEAP_REALLOC_IN_PLACE_ONLY,
RAO_ZEROMEMORY_NOSERIALIZE_GENERATESEXCEPTIONS
= HEAP_ZERO_MEMORY |
HEAP_NO_SERIALIZE |
HEAP_GENERATE_EXCEPTIONS,
RAO_ZEROMEMORY_NOSERIALIZE_REALLOCINPLACEONLY
= HEAP_ZERO_MEMORY |
HEAP_NO_SERIALIZE |
HEAP_REALLOC_IN_PLACE_ONLY,
RAO_ZEROMEMORY_GENERATESEXCEPTIONS_REALLOCINPLACEONLY
= HEAP_ZERO_MEMORY |
HEAP_GENERATE_EXCEPTIONS |
HEAP_REALLOC_IN_PLACE_ONLY,
RAO_NOSERIALIZE_GENERATESEXCEPTIONS_REALLOCINPLACEONLY
= HEAP_NO_SERIALIZE |
HEAP_GENERATE_EXCEPTIONS |
HEAP_REALLOC_IN_PLACE_ONLY,
RAO_ZEROMEMORY_NOSERIALIZE_GENERATESEXCEPTIONS_REALLOCINPLACEONLY
= HEAP_ZERO_MEMORY |
HEAP_NO_SERIALIZE |
HEAP_GENERATE_EXCEPTIONS |
HEAP_REALLOC_IN_PLACE_ONLY
};

enum EnSizeOptions
{
SO_DEFAULT = 0,
SO_NO_SERIALIZE = HEAP_NO_SERIALIZE
};

enum EnFreeOptions
{
FO_DEFAULT = 0,
FO_NO_SERIALIZE = HEAP_NO_SERIALIZE
};

enum EnCompactOptions
{
CPO_DEFAULT = 0,
CPO_NO_SERIALIZE = HEAP_NO_SERIALIZE
};

public:
PVOID Alloc(DWORD size, EnAllocOptions options = AO_DEFAULT)
{return ::HeapAlloc(m_heap, options, size);}

PVOID ReAlloc(PVOID pvmem, DWORD size, EnReAllocOptions options = RAO_DEFAULT)
{return ::HeapReAlloc(m_heap, options, pvmem, size);}

DWORD Size(PVOID pvmem, EnSizeOptions options = SO_DEFAULT)
{return (DWORD)::HeapSize(m_heap, options, pvmem);}

BOOL Free(PVOID pvmem, EnFreeOptions options = FO_DEFAULT)
{return ::HeapFree(m_heap, options, pvmem);}

DWORD Comapct(EnCompactOptions options = CPO_DEFAULT)
{return (DWORD)::HeapCompact(m_heap, options);}

BOOL IsValid() {return m_heap != NULL;}

public:
CPrivateHeap(EnCreateOptions options = CO_DEFAULT, DWORD initsize = 0, DWORD maxsize = 0)
{m_heap = ::HeapCreate(options, initsize, maxsize);}

~CPrivateHeap() {if(IsValid()) ::HeapDestroy(m_heap);}

private:
CPrivateHeap(const CPrivateHeap&);
CPrivateHeap operator = (const CPrivateHeap&);

private:
HANDLE m_heap;
};

template<class T>
class CPrivateHeapBuffer
{
public:
CPrivateHeapBuffer( CPrivateHeap& heap,
DWORD size = 0,
CPrivateHeap::EnAllocOptions allocoptions = CPrivateHeap::AO_DEFAULT,
CPrivateHeap::EnFreeOptions freeoptions = CPrivateHeap::FO_DEFAULT)
: m_hpPrivate(heap)
, m_opFree(freeoptions)
{
ASSERT(m_hpPrivate.IsValid());
m_pvMemory = (T*)m_hpPrivate.Alloc(size * sizeof(T), allocoptions);
}

~CPrivateHeapBuffer() {m_hpPrivate.Free(m_pvMemory, m_opFree);}

T* ReAlloc(DWORD size, CPrivateHeap::EnReAllocOptions options = CPrivateHeap::RAO_DEFAULT)
{return m_pvMemory = (T*)m_hpPrivate.ReAlloc(m_pvMemory, size * sizeof(T), options);}

DWORD Size(CPrivateHeap::EnSizeOptions options = CPrivateHeap::SO_DEFAULT)
{return m_hpPrivate.Size(m_pvMemory, options);}

operator T* () const {return m_pvMemory;}

private:
CPrivateHeapBuffer(const CPrivateHeapBuffer&);
CPrivateHeapBuffer operator = (const CPrivateHeapBuffer&);

private:
CPrivateHeap& m_hpPrivate;
T* m_pvMemory;
CPrivateHeap::EnFreeOptions m_opFree;
};

typedef CPrivateHeapBuffer<BYTE> CPrivateHeapByteBuffer;
typedef CPrivateHeapBuffer<TCHAR> CPrivateHeapStrBuffer;

 

  上述代碼看起來挺復雜,但使用起來卻是異常簡單的,請看下面的使用示例:

// 全局可見的 Heap
CPrivateHeap g_heap;

class MyClass
{
private:
// 與類實例生命周期一致的 Heap
CPrivateHeap m_heap;

// 僅類內部可見的 Heap
static CPrivateHeap sm_heap;

public:
void test_m_eap()
{
// 無需顯式釋放堆內存
CPrivateHeapStrBuffer buff(m_heap, 32);
lstrcpy(buff, _T("失敗乃成功之母"));
DWORD size = buff.Size();
buff.ReAlloc(40 * sizeof(TCHAR));
size = buff.Size();
std::cout << (TCHAR*)buff << '\n';
}

static void test_sm_eap()
{
CPrivateHeapStrBuffer buff(sm_heap, 32);
lstrcpy(buff, _T("失敗乃成功之母"));
DWORD size = buff.Size();
buff.ReAlloc(40 * sizeof(TCHAR));
size = buff.Size();
std::cout << (TCHAR*)buff << '\n';
}
};

void test_g_heap()
{
// 如果不使用 CPrivateHeapBuffer<T> 來封裝堆內存

ASSERT(g_heap.IsValid());
TCHAR* pch = (TCHAR*)g_heap.Alloc(32 * sizeof(TCHAR));
lstrcpy(pch, _T("失敗乃成功之母"));
DWORD size = g_heap.Size(pch);
g_heap.ReAlloc(pch, 40 * sizeof(TCHAR));
size = g_heap.Size(pch);
std::cout << pch << '\n';

// 需要顯式釋放堆內存
g_heap.Free(pch);
}

int _tmain(int argc, _TCHAR* argv[])
{
test_g_heap();

MyClass::test_sm_eap();

MyClass c;
c.test_m_eap();

return 0;
}



 

CodeProject


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM