C++简单实现GC和内存池
??C++簡單實現(xiàn)GC和內(nèi)存池
? 本章前言:
??? 這章就是為了避開傳統(tǒng)的new\delete創(chuàng)建堆對象的手法,如果使用不當指針容易出現(xiàn)問題,所以本章簡單的實現(xiàn)了引用計數(shù)垃圾回收,使用起來貌似還不錯。Bug還有待測試。
? 最終效果:
??? 通過DND_GC_CLASS宏來定義一個Student類后,用戶還是能通過正常的方法使用Student類。但宏額外生成了HStudent類,通過這個類就能方便的實現(xiàn)自動垃圾回收(類似C#中引用變量的效果)。
#include "DNDGC.h"
DND_GC_CLASS(Student)
public:
??? int id;
??? char data[40000];
??? Student():
??? id(0){}
??? void Init(intidi)
??? {
??????? id = idi;
??? }
??? bool operator<(constStudent& b)
??? {
??????? return id <b.id;
??? }
};
??? 首先定義一個空引用,它未指向任何值:
HStudent stu;
??? 調(diào)用Initalize()實例化對象,這里實際分配內(nèi)存空間:
stu.Initalize();
??? 當stu指向的堆內(nèi)存沒有任何H句柄對象指向時就會被內(nèi)存池標記為可用,從而給予其它對象使用。Student的成員函數(shù)通過->操作符訪問。
? 具體實現(xiàn):
??? 首先實現(xiàn)一個簡單的動態(tài)數(shù)組模板類Vector:
??? template<typenameT>
??? class Vector
??? {
??? public:
??????? T& operator[](unsignedi)
??????? {
??????????? assert(i <m_size);
??????????? return m_vector[i];
??????? }
??????? T& At(unsignedi)
??????? {
??????????? while(i >=m_size)
??????????????? _extend();
??????????? return m_vector[i];
??????? }
??????? Vector() :
??????????? m_vector(newT[1]),
??????????? m_size(1){}
??????? Vector(unsignedsize) :
??????????? m_vector(newT[size]),
??????????? m_size(size){}
??????? ~Vector()
??????? {
??????????? delete[] m_vector;
??????? }
??????? unsigned GetSize(){return m_size;}
??? private:
??????? T* m_vector;
??????? unsigned m_size;
??????? void _extend()
??????? {
??????????? m_size<<= 1;
??????????? T* temp =new T[m_size];
??????????? memcpy_s(temp,m_size, m_vector,m_size);
??????????? delete[] m_vector;
??????????? m_vector = temp;
??????? }??
??? };
?
??? 接著實現(xiàn)內(nèi)存池模板類,包含一個含vector節(jié)點的鏈表。當程序需要更多內(nèi)存時,就會創(chuàng)建新的Vector節(jié)點。每個節(jié)點依次是2^(n-1)個元素。如果用戶需要一個內(nèi)存,就通過查詢內(nèi)存所在變量的引用計數(shù)是否為0,是就說明沒人使用,就返回此地址。
??? template<classT>
??? class PoolArray
??? {
??? private:
??????? //頁面組(一個頁面就是一個數(shù)組而已)
??????? std::list<Vector<T>*>m_pages;
??? public:
??????? //構造時初始化第一個頁,大小為1
??????? PoolArray()
??????? {
??????????? //注意類型是指針
??????????? Vector<T>*a = new Vector<T>(1);
??????????? std::cout<< "使用內(nèi)存:"<< (sizeof(T)) / 1024.0f<< "KB"<< std::endl;
??????????? m_pages.push_back(a);
??????? }
??????? //要取一個位置
??????? T* GetSite()
??????? {
??????? loop:
??????????? unsigned num = 0;
??????????? for (autoiter = m_pages.begin();iter != m_pages.end(); ++iter)
??????????? {
??????????????? Vector<T>*a = *iter;
??????????????? for (unsignedi = 0; i < a->GetSize(); ++i)
??????????????? {
??????????????????? GCObject* obj = (GCObject*)&((*a)[i]);
??????????????????? if (obj->m_refNum == 0)
??????????????????? {
??????????????????????? obj->m_refNum++;
??????????????????????? return (T*)obj;
??????????????????? }
??????????????? }
??????????????? num += a->GetSize();
??????????? }
??????????? //沒有空位,則添加新頁,為以前總和的兩倍
??????????? Vector<T>*next = new Vector<T>(num<< 1);
??????????? std::cout<< "使用內(nèi)存:"<< ((num << 1) * sizeof(T)) /1024.0f << "KB"? << std::endl;
??????????? m_pages.push_back(next);
??????????? goto loop;
??????? }
??????? //析構,結束程序的時候調(diào)用
??????? ~PoolArray()
??????? {
??????????? for (autoiter = m_pages.begin();iter != m_pages.end(); ++iter)
??????????? {
??????????????? Vector<T>*a = *iter;
??????????????? std::cout<< "釋放內(nèi)存:"<< (a->GetSize() *sizeof(T)) / 1024.0f<< "KB"<< std::endl;
??????????????? delete a;
??????????? }
??????? }
???????
??? };
??? 其中使用內(nèi)存和釋放內(nèi)存的地方寫有調(diào)試語句,效果如下:
???
??? 接著寫個接口讓程序來調(diào)用,其中staticPoolArray<T> a用來存儲內(nèi)存池用到的內(nèi)存:
??? class Mempool
??? {
??????? //用戶禁止使用
??? private:
??????? Mempool() {};
??????? //查找T類型的auto_array
??????? template<classT>
??????? static PoolArray<T>&FindPoolArray()
??????? {
??????????? static PoolArray<T>a;
??????????? return a;
??????? }
??? public:
??????? //返回指定類型的內(nèi)存池地址
??????? template<classT>
??????? static T*GetSite()
??????? {
??????????? return FindPoolArray<T>().GetSite();
??????? }
??? };
如果代碼中想要分配指定類型的一塊內(nèi)存就應該調(diào)用Mempool::GetSite<TypeName>()。但規(guī)定是T得繼承于GCObject類。
class GCObject
{
??? //friend class DND::Mempool;
??? template<classT>
??? friend classDND::PoolArray;
public:
??? unsigned GetRefNum()
??? {
??????? return m_refNum;
??? }
??? void PrintTypeName()
??? {
??????? std::cout<< typeid(this).name()<< std::endl;
??? }
??? unsigned m_refNum;
??? GCObject() : m_refNum(0){}
??? virtual booloperator<(const GCObject& b)
??? {
??????? return true;
??? }
};
??? GCObject類主要包含引用計數(shù)變量,使用此框架的類都應該繼承它。DND_GC_CLASS宏就讓參數(shù)繼承它,并為其生成一個H開頭的句柄類。
#define DND_GC_CLASS(ClassName)\
class ClassName;\
class H##ClassName\
{\
public:\
??? ClassName* operator->(){assert(m_p &&"This is null reference!"); return (ClassName*)m_p;}\
??? ~H##ClassName(){if(m_p&& !--m_p->m_refNum){m_p = 0;}}\
??? H##ClassName(): m_p(0){}\
??? H##ClassName(constH##ClassName&b){m_p = (GCObject*)b.m_p;++m_p->m_refNum;}\
??? H##ClassName&operator=(constH##ClassName& b){if(m_p&& !--m_p->m_refNum){m_p = 0;}m_p = (GCObject*)b.m_p;++m_p->m_refNum;return *this;}\
??? bool operator<(constH##ClassName& b){return *m_p < *b.m_p;}\
??? void Initalize(){if(m_p && !--m_p->m_refNum){m_p = 0;} m_p = (GCObject*)DND::Mempool::GetSite<ClassName>();}\
private:\
??? GCObject* m_p;\
??? static void*operator new(size_tsize){};\
??? static voidoperator delete(void*ptr){};\
};\
class ClassName : privateGCObject\
{\
??? friend classH##ClassName;\
最后我做了一下測試,對比了和直接new/delete的速度差距:
??????? DWORD t1 = GetTickCount();
??????? unsigned i =REPLAY_COUNT;
??????? while (i--)
??????? {
??????????? //STU_NUMBER個
??????????? HStudent stu3[STU_NUMBER];
??????????? for (unsignedi = 0; i != STU_NUMBER; ++i)
??????????? {
??????????????? stu3[i].Initalize();
??????????????? //stu3[i]->Print();
??????????? }
??????? }
??????? DWORD t2 = GetTickCount();
??????? std::cout<< "花費時間:"<< t2 - t1? << "ms"<< std::endl;
??????? //
??????? t1 = GetTickCount();
??????? i = REPLAY_COUNT;
??????? while (i--)
??????? {
??????????? Student* stu4 = new Student[STU_NUMBER];
??????????? delete stu4;
??????? }
??????? t2 = GetTickCount();
??????? std::cout<< "花費時間:"<< t2 - t1 << "ms"<< std::endl;
得出的數(shù)據(jù)如下:
?
作者:略游
日期:17-07-22
QQ:1339484752
總結
以上是生活随笔為你收集整理的C++简单实现GC和内存池的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 4.使用pnglib读写png图片
- 下一篇: 让Win32窗口程序拥有控制台窗口