ice3.3.1中GC算法的實現


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




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章