C++和Java解決智能指針或?qū)ο笱h(huán)引用的策略

https://zwmf.iteye.com/blog/1738574

C++

class CDog;
class CTail
{
public:
    void RegisterDog(const std::shared_ptr<CDog>& ptr_dog)
    {
        m_dog_ = ptr_dog;
    }
private:
    std::weak_ptr<CDog> m_dog_ ;
};

class CDog
{
public:
    void RegisterTail(const std::shared_ptr<CTail>& ptr_tail)
    {
        m_tail_ = ptr_tail;
    }
private:
    std::shared_ptr<CTail> m_tail_ = nullptr;
};


// 測(cè)試智能指針
void TestRefPtr()
{
    std::shared_ptr<CDog> ptr_dog = make_shared<CDog>();
    std::shared_ptr<CTail> ptr_tail = make_shared<CTail>();
    ptr_dog->RegisterTail(ptr_tail);
    ptr_tail->RegisterDog(ptr_dog);
    cout << "ptr_dog count:" << ptr_dog.use_count()<<endl;
    cout << "ptr_tail count:" << ptr_tail.use_count() << endl;
}

int main()
{
    
    TestRefPtr();
    return 0;
}

Java

在C++中使用過(guò)智能指針的同學(xué)們應(yīng)該都清楚智能指針對(duì)C++中內(nèi)存管理帶來(lái)的極大便利,但是也會(huì)引入一些頭疼的問(wèn)題,比如智能指針帶來(lái)的循環(huán)引用的問(wèn)題,這個(gè)問(wèn)題在之前的項(xiàng)目中一直沒(méi)有很好的解決。

    最近參與到android的項(xiàng)目開(kāi)發(fā),對(duì)java的內(nèi)存的管理有了一個(gè)初步的了解,很容易想到了循環(huán)引用的問(wèn)題。比如下面這個(gè)例子:

    public void buidDog()

    {

       Dog newDog = new Dog();

      Tail newTail = new Tail();

      newDog.tail = newTail;

      newTail.dog = newDog;

    }

    在這里,newTail中拿著對(duì)newDog的引用,newDog中拿著對(duì)newTail的引用。如果newDog要被回收,前提是newTail被先回收,這樣才能釋放對(duì)newDog的引用。但是反回過(guò)來(lái),newTail要被回收的前提是newDog要被先回收。當(dāng)buildDog函數(shù)退出后,看起來(lái)垃圾回收管理似乎就始終無(wú)法回收這兩個(gè)實(shí)際已經(jīng)不再需要的對(duì)象。

     垃圾回收機(jī)制究竟能否解決循環(huán)引用這一困境,帶著這個(gè)疑問(wèn)找了一些資料,找到了一個(gè)比較滿意的解釋。在《Java Platform Performance: Strategies and Tactics》這本書(shū)的附錄A中有一處說(shuō)明,這本書(shū)出自sun公司java團(tuán)隊(duì)員工,應(yīng)該算比較權(quán)威的。其中有這樣一段([http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html#997428](http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html#997428)):

“It's important to note that not just any strong reference will hold an object in memory.

These must be references that chain from a garbage collection root. 

GC roots are a special class of variable that includes 

Temporary variables on the stack (of any thread)

    Static variables (from any class)

    Special references from JNI native code”。

這段話可以簡(jiǎn)單的理解就是強(qiáng)引用并不能保證對(duì)象不被回收。垃圾回收機(jī)制除了檢查對(duì)象是否被引用外,還要看對(duì)象是否被至少一個(gè)GC roots對(duì)象直接或者間接引用。GC roots對(duì)象包括以下一些類容:

1 每個(gè)線程當(dāng)前的函數(shù)調(diào)用棧,從棧頂?shù)綏5椎拿總€(gè)函數(shù)里的局部變量。

2 靜態(tài)的變量

3 被jni中引用到的變量。

    所以,上面例子中兩個(gè)循環(huán)引用的對(duì)象,雖然都存在一個(gè)強(qiáng)引用,但是不被任何GC root對(duì)象直接或者間接引用到,垃圾回收機(jī)制能夠發(fā)現(xiàn)這個(gè)問(wèn)題。

    另外,為了驗(yàn)證這一點(diǎn),特意翻看了一下android源碼中GC管理這一塊的代碼。在MarkSweep.c這文件中,有一個(gè)void dvmHeapMarkRootSet()函數(shù),這個(gè)函數(shù)對(duì)于GC root對(duì)象,有一些詳細(xì)的說(shuō)明,有興趣的可以細(xì)看一下。

    所以,java對(duì)于循環(huán)引用有一套自己的解決方案。但是話又說(shuō)回來(lái),一般實(shí)際編碼中出現(xiàn)的循環(huán)引用不會(huì)是上面那個(gè)例子那樣明顯,一般都是多個(gè)對(duì)象復(fù)雜的引用導(dǎo)致的循環(huán),這個(gè)時(shí)候,如果一個(gè)對(duì)象的生命周期很長(zhǎng),就會(huì)導(dǎo)致多個(gè)對(duì)象都釋放不了,所以還是要特別留意對(duì)象之間的引用關(guān)系。

轉(zhuǎn)載于:http://blog.sina.com.cn/s/blog_6a0eedb60100y76b.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 今天是考科目二的日子。昨晚回來(lái)的路上,我的教練二姨對(duì)我說(shuō):小麗啊,明天早上我再帶你進(jìn)場(chǎng)地練練,別和她們講。我就不帶...
    二十一行閱讀 212評(píng)論 0 1
  • 馬上畫(huà)
    一帆風(fēng)順吶閱讀 307評(píng)論 2 0
  • book chart 3 仿射函數(shù)(即線性函數(shù))為凸/凹函數(shù) 其他例子1.png2.png3.png4.png J...
    生病喝藥水閱讀 449評(píng)論 0 0
  • 雷雁雄8月20日總結(jié):今天在家休息,兒子也旅游回來(lái)了,給每個(gè)人都帶回小禮品,第一次出去旅游也能想到家里人并給帶禮物...
    雷雁雄閱讀 293評(píng)論 0 0

友情鏈接更多精彩內(nèi)容