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