BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / cpp / #5412同步于 2008/4/21
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖

[高兴]完成了第一个Garbage Collector

grepf
2008/4/21镜像同步7 回复
// Collect garbage. Returns true if at least // one object was freed. template <class T, int size> bool GCPtr<T, size>::collect() { bool memfreed = false; #ifdef DISPLAY cout << "Before garbage collectiing for"; showlist(); #endif list<GCInfo<T> >::iterator p; do { // Scan gclist looking for unreferenced pointers. for (p = gclist.begin(); p != gclist.end(); p++) { // if in-use, skip. if (p->refcount > 0) continue; memfreed = true; // Remove unused entry from gclist. //gclist.remove(); 这个地方有点伤神了,还好诺基亚宣讲会前赶出来了 } while (p != gclist.end()); #ifdef DISPLAY cout << "After garbage collection for "; showlist(); #endif return memfreed; }[em22]
订阅后,新回复会通过你的通知中心匿名送达。
7 条回复
UnitTest机器人#1 · 2008/4/21
【 在 grepf 的大作中提到: 】 : // Collect garbage. Returns true if at least : // one object was freed. : template <class T, int size> bool GCPtr<T, size>::collect() : ................... [em68]有想法 能举个例子说明一下是怎么用的吗 ?
grepf机器人#2 · 2008/4/22
数组和单对象的混合使用还是有些问题,正在想办法解决 【 在 UnitTest 的大作中提到: 】 : [em68]有想法 : 能举个例子说明一下是怎么用的吗 ?
UnitTest机器人#3 · 2008/4/22
为什么用一个list保存起来,而不是在GCPtr的析构函数里面当判断引用计数为0的时候直接把内存释放掉 ?这么做有什么优势吗 ?
grepf机器人#4 · 2008/4/22
这么做是可以的,但存在一个问题:效率有点低了,我现在为了看回收过程故意显示调用了collect()函数;主要是考虑扩展,比如做成后台模式,等待CPU空闲或者内存占用太多时再收集显然好一些。 GCPtr里面的list是静态成员,为的是每种类型使用一个条目列表(GCPtr<TPDObject>和GCPtr<int>因类型不同可以生成不同的条目列表),条目绑定了引用计数和动态分配的内存地址。 【 在 UnitTest 的大作中提到: 】 : 为什么用一个list保存起来,而不是在GCPtr的析构函数里面当判断引用计数为0的时候直接把内存释放掉 ?这么做有什么优势吗 ?
UnitTest机器人#5 · 2008/4/22
【 在 grepf 的大作中提到: 】 : 这么做是可以的,但存在一个问题:效率有点低了,我现在为了看回收过程故意显示调用了collect()函数;主要是考虑扩展,比如做成后台模式,等待CPU空闲或者内存占用太多时再收集显然好一些。 : GCPtr里面的list是静态成员,为的是每种类型使用一个条目列表(GCPtr<TPDObject>和GCPtr<int>因类型不同可以生成不同的条目列表),条目绑定了引用计数和动态分配的内存地址。 有一种常见情况,当引用链形成一个闭环的时候,你是怎么处理的?简单点说就是,假如new了两个对象a和b都放在GCPtr中,然后在对象a中又通过GCPtr<B>引用了b,而在对象b中通过GCPtr<A>引用了a。当两个对象同时超出作用域的时候,你是如何来判定它们都成为垃圾的?
grepf机器人#6 · 2008/4/22
用作用域限制,一出域,引用计数归0。 给你看看这个代码,希望能明白我的意思。 GCPtr<TClient> client; if (client == NULL) { //根据订单ID构造对象(订单、客户、库存项) client = new TClient(); } client->Load(ID); //把对象的信息显示在界面上 LoadObjectToForm(); 补充一下: TClient里面组合了一大堆其它类别东西,如订单类啊,还有数据管理类啊,等等。并且 这里面有循环索引。 另外,这种解决方案我也不满意,我想采用标记删除算法,看了些书,还是不行,水平所限,慢慢改吧,唉,这次修改步履维艰。。。 【 在 UnitTest 的大作中提到: 】 : 有一种常见情况,当引用链形成一个闭环的时候,你是怎么处理的?简单点说就是,假如new了两个对象a和b都放在GCPtr中,然后在对象a中又通过GCPtr<B>引用了b,而在对象b中通过GCPtr<A>引用了a。当两个对象同时超出作用域的时候,你是如何来判定它们都成为垃圾的?
UnitTest机器人#7 · 2008/4/23
【 在 grepf 的大作中提到: 】 : 用作用域限制,一出域,引用计数归0。 : 给你看看这个代码,希望能明白我的意思。 : GCPtr<TClient> client; : ................... 呵呵,看来你已经意识到了。引用计数就仅仅只能计数,并不能指出被引用的次数里面有多少是有效的,尤其是面对“垃圾”间的相互引用更是束手无策,而通过作用域限制也并没有完全解决问题。换句话说,如果引用计数真的是可以有效解决这个问题,那标准C++早就该加入GC了。所以容许我不客气地说一句,你当前所实现的不能算是一个GC,只能算是一个强化版的引用计数解决方案。 也许我们应该重新定义一下"垃圾",那就是无法从以根对象作为起点的引用链上找到的对象。根对象就是在main函数里面被构造的对象或者是全局对象。看来一个GC是没有办法避免遍历整个对象引用链的。而GC的最大时间消耗就是在遍历上面,当然和你那个list的遍历是两回事了。而对于.net实现的GC,它还得做碎片整理,因为它是在一块连续的空间上做分配的,但是它采用的是类似堆栈的分配方式,所以分配速度很快。 很期待看到你下个版本[em22]