Lyt
posts - 16,comments - 61,trackbacks - 0

之前已经介绍过垃圾收集器的工作机制了,这篇文章主要针对垃圾收集器的总体设计。

容易看到,垃圾收集器分成两个区域,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)  编辑 收藏 引用 所属分类: 垃圾收集器

FeedBack:
# re: 稚嫩版垃圾收集器 之 具体实现(一)
2010-05-14 16:04 | 陈梓瀚(vczh)
万一你的generation不够大,决定再次申请一个更大的Data的时候,你的Handle里面的Data岂不是变不了了?你应该把一个Heap的指针放进去才是。  回复  更多评论
  
# re: 稚嫩版垃圾收集器 之 具体实现(一)
2010-05-14 16:39 | Lyt
@陈梓瀚(vczh)
Generation不够大就开始垃圾收集了,把存活对象提升到更高的Generation,如果内存还是不够,我就抛出异常了。
Geneation的大小一开始就折腾成固定的,不知道要根据什么规律把它弄成活的才合适。
你的意思是让我把Heap指针放到Generation里?  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理