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è)比較滿(mǎn)意的解釋。在《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”糯累。
這段話(huà)可以簡(jiǎn)單的理解就是強(qiáng)引用并不能保證對(duì)象不被回收算利。垃圾回收機(jī)制除了檢查對(duì)象是否被引用外,還要看對(duì)象是否被至少一個(gè)GC roots對(duì)象直接或者間接引用泳姐。GC roots對(duì)象包括以下一些類(lèi)容:
1 每個(gè)線(xiàn)程當(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)引用有一套自己的解決方案朦蕴。但是話(huà)又說(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