ice3.3.1中GC算法的实现

本文介绍了C++中内存管理的关键概念,包括智能指针、引用计数和垃圾回收算法。通过使用C++的GCShared类,实现了对象的引用计数和自动内存管理,有效防止了内存泄漏。特别地,文中详细解释了如何在类间存在循环引用时,通过自定义垃圾回收器来解决内存管理问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


c++中没有自动的垃圾回收机制,往往程序需要手工管理内存,智能指针以及引用计数的机制对内存管理进行了一个很好的封装,唯一的缺点就是在指针循环引用的情况下不能正确释放内存,最好的解决方法当然就是尽量不要出现循环依赖的情况,但如果实在避免不了建议自行实现一个GC即垃圾回收器。下面是ice3.3.1中GC的算法.

在介绍算法前先介绍下有关的数据结构:


typedef std::set<IceInternal::GCShared*> GCObjectSet;

GCObjectSet gcObjects;

typedef ::std::map<GCShared*, int> GCCountMap; // first 表示对象引用,second表示引用次数


GCShared类介绍:

GCShared类成员函数: __gcIncRef();  引用计数加,首次加时将对象引用插入gcObjects

GCShared类成员函数:__gcDecRef(); 引用计数减,末次减时将对象引用从gcObjects删除

GCShared类成员函数: __addObject(GCCountMap&_c) {} 默认实现为空 ,子类中实现是将自己插入_c 中,或如果已经在_c中,累加second引用次数

GCShared类成员函数:__gcReachable(GCCountMap&)  纯虚函数接口,由子类实现

GCShared类成员函数:__gcClear()   纯虚函数接口,由子类实现

GCShared类成员函数:__usesClasses() { return false; }   默认实现返回false


::Ice::Object: public IceInternal::GCShared,在类ice中__gcReachable,__gcClear2个函数的默认实现都为空


凡是需要进行GC的类都必须继承GCShared

凡是有类成员的类都自动生成__gcReachable,__gcClear()函数的实现,__usesClasses()函数返回true,在__gcReachable函数中对所有类成员对象调用__addObject(GCCountMap&_c)函数,

凡是有类成员的类都自动生成生成__incRef(),__decRef(),分别调用__gcIncRef(),__gcDecRef(), 这样凡是有类成员的类对象的引用都将在gcObjects中存在,

没有类成员的对象不会存在循环引用的情况,所以不需要考虑。


GC算法:

1   GCCountMap counts;  遍历gcObjects,将所有有类成员的对象,以及引用的次数放入counts中

     GCCountMap reachable; 遍历gcObjects, 调用所有对象上的__gcReachable(reachable)函数, 这样将所有以成员身份的引用次数计入到reachable


2  将 counts中所有在reachable中存在的对象的引用次数减去reachable中的引用次数,得到非以成员引用的次数,如果大于0表示对象是活动的。


3 GCObjectSet liveObjects; 遍历counts所有引用计数大于0的对象放入liveObjects,并且对counts所有对象的有类成员的类成员递归遍历放入liveObjects


4 从counts中移除所有在liveObjects中存在的对象,剩下的便是要回收的对象,对所有要回收的对象先调用__gcClear(),再删除。


例如  A ->B ,B->A  的情况,AB都是有类成员的对象:

步骤1中,将A,B分别插入counts中,引用次数都是2, 对A,B分别调用一次__gcReachable(reachable)函数,reachable中对A,B引用次数都是1

步骤2,3中 得到AB以非成员方式引用的次数都是1,即活动的,如果过了A,B的生命域,那么步骤1中计算A,B插入counts中,引用次数都是1


对于A ->B ,B->C  的情况,假设C是无类成员的对象

步骤1中,将A,B分别插入counts中,引用次数都是1    对于   A,B  分别调用一次__gcReachable(reachable)函数,reachable中对B引用次数都是1,无AC,

步骤2得到A是活动的,B的引用次数为0

步骤3后从A开始递归遍历所有的有类成员的对象得到B又是活动的

总结:  

步骤1 是算出所有有类成员的类对象被引用的总次数,然后算出所有有类成员的类对象以类成员的方式引用的次数

步骤2将步骤1中2者相减得到以非成员方式引用的所有的活动的类对象

步骤3对所有步骤2中活动的类对象进行递归,将所有有类成员的成员也加入到活动的类对象中

步骤4 删除所有活动的对象,便是需要回收的对象。



example: 


class C
{
    A left;
};

对于有类成员的类C将自动生成以下代码:

void
Test::C::__incRef()
{
    __gcIncRef();
}


void
Test::C::__decRef()
{
    __gcDecRef();
}

bool
Test::C::__usesClasses()
{
    return true;
}


void
Test::C::__gcReachable(::IceInternal::GCCountMap& _c) const
{
    if(left)
    {
        ::IceInternal::upCast(left.get())->__addObject(_c);
    }
}


void
Test::C::__gcClear()
{
    if(left)
    {
        if(::IceInternal::upCast(left.get())->__usesClasses())
        {
            ::IceInternal::upCast(left.get())->__decRefUnsafe();
            left.__clearHandleUnsafe();
        }
        else
        {
            left = 0;
        }
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值