android模拟gc回收,c++ 模拟gc垃圾回收

说明:代码实现借鉴这边文章

查找及回收无用对象的方法有很多种,最简单也是最早的一种方法,叫“标记-清除法”。 过程:

从根对象开始,遍历整个对象图。每访问一个对象,就把一个标记位设成true。

一旦完成遍历,找出所有没有被标记过的对象,并清除掉它们。 假设我们正在写一门小语言的解释器。它是动态类型的,有两种对象:int以及pair。下面是一个定义对象类型的枚举:

#include

enum Obj_Type

{

OBJ_INT,

OBJ_PAIR

};

实现对象类型:

struct _Object

{

Obj_Type type;

unsigned char marked;//标记标志,如果被标记,说明可达。

//union

//{

int value;//存储的值

struct

{

_Object* pHead;

_Object* pTail;

};

//};

_Object *pNext;

};

现在我们可以把它们封装到一个小型虚拟机的结构里了。这个虚拟机在这的作用就是持有一个栈,用来存储当前使用的变量。很多语言的虚拟机都要么是基于栈的(比如JVM和CLR),要么是基于寄存器的(比如Lua)。不管是哪种结构,实际上它们都得有一个栈。它用来存储本地变量以及表达式中可能会用到的中间变量。

#define MAX_SIZE 256 //堆栈最大数目

#define INITIAL_GC_THRESHOLD 128 //触发gc的对象数量

typedef struct _tagVM

{

_Object* objs[MAX_SIZE];

int max_objs;//产生的最大对象的数目,超过调用gc

int num_objs;//记录现在的对象数目

//对虚拟机层面,所有的对象应该都是可见的,从用户角度,有些对象可能没有任何引用指向它,对象也就

//不可见,所以

//用链表记录通过虚拟机产生的所有对象。

_Object *pFirstObj;//链表的头指针

_Object *pLastObj;//链表的尾指针

int objs_size;//堆栈大小或者堆栈指针

}VM;

创建虚拟机的函数:

VM* new_VM()

{

VM *pVm=(VM *)malloc(sizeof(VM));

pVm->objs_size=0;

_Object *pObj=create_obj(OBJ_INT);

pObj->value=0;

pObj->marked=1;

pObj->pHead=NULL;

pObj->pTail=NULL;

pObj->pNext=NULL;

pVm->pFirstObj=pObj;//NULL;第一个节点不使用,

pVm->pLastObj=pVm->pFirstObj;

pVm->max_objs=INITIAL_GC_THRESHOLD;

pVm->num_objs=0;

return pVm;

}

释放虚拟机函数:

void delete_VM(VM *pVM)

{

_Object *pObj=pVM->pFirstObj;

while (pObj!=NULL)

{

printf("%i\t",pObj->value);

_Object *tmp=pObj->pNext;

delete_Obj(pObj);

pObj=tmp;

}

free(pVM);

pVM=NULL;

}

有了虚拟机后,我们需要对它的栈进行操作:

void push(VM* pVM,_Object *pObj)

{

assert(pVM->objs_size<=MAX_SIZE ,"Stack overflow!");

pVM->num_objs++;

pVM->pLastObj->pNext=pObj;

pVM->pLastObj=pObj;

pVM->objs[pVM->objs_size++]=pObj;

if (pVM->num_objs>pVM->max_objs)

{

gcVM(pVM);

}

}

_Object * pop(VM*pVM)

{

assert(pVM->objs_size>0 ,"Stack underflow!");

return pVM->objs[--pVM->objs_size];

}

产生对象的函数:

_Object * create_obj(Obj_Type type)

{

_Object *pObj=(_Object *)malloc(sizeof(_Object));

pObj->type=type;

pObj->marked=0;

pObj->pNext=NULL;

return pObj;

}

_Object * new_obj(Obj_Type type)

{

_Object *pObj=create_obj(type);

return pObj;

}

有了它我们就可以把不同类型的对象压到栈里了:

void push_int(VM* pVM,int value)

{

_Object *pObj=new_obj(pVM,OBJ_INT);

pObj->value=value;

push(pVM,pObj);

}

_Object * push_pair(VM* pVM,int value)

{

_Object *pObj=new_obj(pVM,OBJ_PAIR);

pObj->value=value;

pObj->pTail=pop(pVM);

pObj->pHead=pop(pVM);

push(pVM,pObj);

return pObj;

}

如果我们有个解析器和解释器来调用这些函数,就是一门完整的语言了。下面是标记-清除过程: 第一个阶段是标记阶段,

void mark(_Object *pObj,unsigned char marked)

{

if (pObj->marked) return;//防止pair类型相互引用,造成环回,形成无穷递归。

printf("%i\t",pObj->value);//调试输出

pObj->marked=marked;

if (pObj->type==OBJ_PAIR)//pair类型,进行递归

{

mark(pObj->pHead,marked);

mark(pObj->pTail,marked);

}

}

void mark_all(VM*pVM)

{

for (int i=0;iobjs_size;++i)

{

//printf("%i\t",pVM->objs[i]->value);

if (pVM->objs[i]->type==OBJ_PAIR)//堆栈中的非Pair节点,认为不可达

{

mark(pVM->objs[i],1);

}

}

}

下一个阶段就是遍历所有分配的对象,释放掉那些没有被标记的了,

void sweep(VM* pVM)

{

_Object *pObj=NULL,*pFrontObj=NULL;

pObj=pFrontObj=pVM->pFirstObj;

while (pObj!=NULL)

{

if (!pObj->marked)

{

printf("%d\t",pObj->value);//调试输出

pFrontObj->pNext=pObj->pNext;//删除链表节点,调整前后指针指向

_Object *tmp=pObj;

pFrontObj=pObj=pFrontObj->pNext;

free(tmp);

pVM->num_objs--;//目前对象数目减一

}

else

{

pFrontObj=pObj;

pObj=pObj->pNext;

}

}

}

最后,有了一个垃圾回收器:

void gcVM(VM*pVM)

{

mark_all(pVM);

sweep(pVM);

//每次回收之后,我们会根据存活对象的数量,更新maxOjbects的值。

//这里乘以2是为了让我们的堆能随着存活对象数量的增长而增长。

//同样的,如果大量对象被回收之后,堆也会随着缩小

pVM->max_objs = pVM->num_objs * 2;

}

然后,我们在new_obj根据对象产生的数目来触发gc。 我们来产生一些对象来测试gc:

int _tmain(int argc, _TCHAR* argv[])

{

VM *pVM=new_VM();

for (int i=0;i<10;++i)//产生一些对象

{

push_int(pVM,10);

push_int(pVM,15);

push_pair(pVM,20);//使堆栈中丢失前面的两个对象指针

push_int(pVM,30);//不可达

}

printf("mark_all:\n");

mark_all(pVM);

printf("sweep:\n");

sweep(pVM);

printf("delete_VM:\n");

delete_VM(pVM);

getchar();

return 0;

}

最终如下:

daf83901c516fb1ba0c1a322d4bb71b1.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值