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