之前已經(jīng)介紹過垃圾收集器的工作機(jī)制了,這篇文章主要針對垃圾收集器的總體設(shè)計(jì)。
容易看到,垃圾收集器分成兩個區(qū)域,SmallObjectHeap存放小型對象,LargeObjectHeap存放大型對象。SmallObjectHeap會進(jìn)行內(nèi)存縮并,而對LargeObjectHeap進(jìn)行內(nèi)存縮并顯然不合適,移動大型對象會花很大代價(jià)。這里強(qiáng)調(diào)下,SamllObjectHeap和LargeObjectHeap各自是一個連續(xù)的內(nèi)存區(qū)域,其中三個分代只是做一下標(biāo)志而已。
class GC
{
private:
static const int LARGE_OBJECT_SIZE; //大型對象最小大小
static const int SMALL_OBJECT_SIZE; //小型對象最小大小
SmallObjectHeap* SmallHeap; //小型對象堆
LargeObjectHeap* LargeHeap; //大型對象堆
Pool<ObjectHandle> ObjectHandlePool;
bool IsLargeObject(const int size)const; //判斷是否為大型對象
public:
void Clear(); //釋放GC申請所有內(nèi)存
ObjectHandle* Alloc(const int size); //分配size大小的對象
void Collect(const int generationIndex=0); //對LarObjectHeap和SmallObjectHeap中第0-generationIndex分代進(jìn)行垃圾收集
void Mark(ObjectHandle* handle); //標(biāo)記對象handle,表示其為存活對象
接下來詳細(xì)介紹下SmallObjectHeap。
class Generation //分代
{
public:
int Start; //開始位置
int Size; //該分代大小
int AllocateIndex; //該分代空閑內(nèi)存起始位置
int Free; //該分代空閑內(nèi)存大小
void Init(const int start, const int size);
bool CanAlloc(const int size)const; //該分代的空閑內(nèi)存是否足以分配size大小的對象
void AfterAlloc(const int size); //分配size大小的對象后更新該分代信息
};
class SmallObjectHeap //小型對象堆
{
private:
static const int TOTAL;
int Total; //真實(shí)內(nèi)存區(qū)域Data的大小
int Free; //空閑內(nèi)存的大小
char* Data; //真實(shí)內(nèi)存區(qū)域
const int GenerationCount; //分多少代
Generation* Generations; //各分代的詳細(xì)信息
ObjectHandleContainer ObjectHandles; //記錄所有分配出去的ObjectHandle,便于垃圾收集的時(shí)候更新信息
public:
void Clear(); //釋放該小型對象堆申請的所有內(nèi)存
ObjectHandle* Alloc(const int size, Pool<ObjectHandle>& ObjectHandlePool); //分配size大小的對象
void Collect(const int generationIndex=0); //對0-generationIndex代進(jìn)行垃圾收集
};
下面我們看下之前一直提到的ObjectHandle。垃圾收集器對外提供的都是ObjectHandle,所有的工作都只能建立在ObjectHandle上而不是針對一個char*,包括標(biāo)記對象、回收內(nèi)存等。這里稍微提一下用ObjectHandle而非直接對char*進(jìn)行操作的好處。我們知道內(nèi)存縮并的時(shí)候,是需要把存活對象的內(nèi)存里的數(shù)據(jù)復(fù)制到別的地方去的,意味著對象所在地內(nèi)存區(qū)域會有變動,而如果這里的垃圾收集器我并不希望有內(nèi)存縮并這個動作,這意味著對象真實(shí)存在的內(nèi)存區(qū)域并不會改變,于是char*是死的,并不會跑,如果我一律都用ObjectHandle.GetPointer()來獲得對象真實(shí)的內(nèi)存區(qū)域,那么一切文章都可以封裝在ObjectHandle里,而沒有必要垃圾收集機(jī)制的改變就大幅度地變動代碼。
enum ObjectHandleType //區(qū)別對象是否被外部指針引用
{
handleNORMAL,
handlePINNED //外部指針指向的對象不可被收集
};
class ObjectHandle
{
private:
char* Data; //內(nèi)存區(qū)域
public:
ObjectHandleType Type; //Handle類型
int Start; //開始位置
int Size; //對象大小
bool Marked; //對象是否被標(biāo)記
void Init(char* data, const int start, const int size, const ObjectHandleType type=handleNORMAL);
void Move(const int index); //將對象移動到指定的位置,參數(shù)為開始位置
char* GetPointer(); //返回對象所在地內(nèi)存區(qū)域,即在Data的基礎(chǔ)上后移Start個位置
};
posted on 2010-05-14 14:44
Lyt 閱讀(1825)
評論(2) 編輯 收藏 引用 所屬分類:
垃圾收集器