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;
}
}
}