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