之前已经介绍过垃圾收集器的工作机制了,这篇文章主要针对垃圾收集器的总体设计。
容易看到,垃圾收集器分成两个区域,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 阅读(1812)
评论(2) 编辑 收藏 引用 所属分类:
垃圾收集器