稚嫩版垃圾收集器 之 具体实现(一)

稚嫩版垃圾收集器 之 具体实现(一)

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

容易看到,垃圾收集器分成两个区域,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个位置
        };

你可能感兴趣的:(稚嫩版垃圾收集器 之 具体实现(一))