@_ root _ build git(main) ./service/example/example I20211119 21:36:41.24918616312 main.cpp:171] Create Peter I20211119 21:36:41.24926116312 main.cpp:176] Destroy Peter
简单的引用计数器不能解决循环引用的问题。
A 引用 B ,B 引用 A,的时候,A不再使用,但是B引用着A,A不能释放。如果把引用分为强引用和弱引用,将引用关系方向化,父-子,子-父,则规定:父引用子为强引用,子引用父为弱引用,当子引用父的时候,父对象不再使用时,父对象生命周期的销毁不受子对象的约束。当释放了父对象,父对子的计数器也会被释放;当子不再使用的时候,子也就安全释放了,因为没有父对象对他进行强引用。总而言之就是:不能释放被强引用的对象,可以释放被弱引用的对象。
void RefBase::weakref_type::decWeak(constvoid* id) { weakref_impl* const impl = static_cast<weakref_impl*>(this); impl->removeWeakRef(id); constint32_t c = linking_atomic_dec(&impl->mWeak); ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this); if (c != 1) return; //是否是最后一次引用计数
if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) { // This is the regular lifetime case. The object is destroyed // when the last strong reference goes away. Since weakref_impl // outlive the object, it is not destroyed in the dtor, and // we'll have to do it here. if (impl->mStrong == INITIAL_STRONG_VALUE) { // Special case: we never had a strong reference, so we need to // destroy the object now. delete impl->mBase; //释放实际对象 } else { // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase); delete impl; //释放mRefs } } else { // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER} impl->mBase->onLastWeakRef(id); if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) { // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference // is gone, we can destroy the object. delete impl->mBase; //弱引用控制,释放实际对象 } } }
稍微总结一下wp的析构过程:
弱引用技术-1
最后一次弱引用时,强引用控制,释放mRefs,若没有强引用,释放实际对象
最后一次弱引用时,弱引用控制,释放实际对象
回到例子当中,此时,强引用计数为1,弱引用计数为1,并没有任何释放。
sp的析构
在例子当中,当wp析构完成之后,sp的作用域也结束了,就会调用到sp的析构函数:
1 2 3 4 5
template<typename T> sp<T>::~sp() { if (m_ptr) m_ptr->decStrong(this); }
RefBase::~RefBase() { if (mRefs->mStrong == INITIAL_STRONG_VALUE) { // we never acquired a strong (and/or weak) reference on this object. delete mRefs; } else { // life-time of this object is extended to WEAK or FOREVER, in // which case weakref_impl doesn't out-live the object and we // can free it now. if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) { // It's possible that the weak count is not 0 if the object // re-acquired a weak reference in its destructor if (mRefs->mWeak == 0) { delete mRefs; } } } // for debugging purposes, clear this. const_cast<weakref_impl*&>(mRefs) = NULL; }
ALOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow", this);
while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) { // we're in the easy/common case of promoting a weak-reference // from an existing strong reference. if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) { break; } // the strong count has changed on us, we need to re-assert our // situation. curCount = impl->mStrong; }
if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) { // we're now in the harder case of either: // - there never was a strong reference on us // - or, all strong references have been released if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) { // this object has a "normal" life-time, i.e.: it gets destroyed // when the last strong reference goes away if (curCount <= 0) { // the last strong-reference got released, the object cannot // be revived. decWeak(id); returnfalse; }
// here, curCount == INITIAL_STRONG_VALUE, which means // there never was a strong-reference, so we can try to // promote this object; we need to do that atomically. while (curCount > 0) { if (android_atomic_cmpxchg(curCount, curCount + 1, &impl->mStrong) == 0) { //强引用控制,强引用计数+1 break; } // the strong count has changed on us, we need to re-assert our // situation (e.g.: another thread has inc/decStrong'ed us) curCount = impl->mStrong; }
if (curCount <= 0) { // promote() failed, some other thread destroyed us in the // meantime (i.e.: strong count reached zero). decWeak(id); returnfalse; } } else { // this object has an "extended" life-time, i.e.: it can be // revived from a weak-reference only. // Ask the object's implementation if it agrees to be revived if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) { // it didn't so give-up. decWeak(id); returnfalse; } // grab a strong-reference, which is always safe due to the // extended life-time. curCount = android_atomic_inc(&impl->mStrong); //弱引用计数+1 }
// If the strong reference count has already been incremented by // someone else, the implementor of onIncStrongAttempted() is holding // an unneeded reference. So call onLastStrongRef() here to remove it. // (No, this is not pretty.) Note that we MUST NOT do this if we // are in fact acquiring the first reference. if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) { impl->mBase->onLastStrongRef(id); } }
impl->addStrongRef(id);
#if PRINT_REFS ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount); #endif
// now we need to fix-up the count if it was INITIAL_STRONG_VALUE // this must be done safely, i.e.: handle the case where several threads // were here in attemptIncStrong(). curCount = impl->mStrong; while (curCount >= INITIAL_STRONG_VALUE) { ALOG_ASSERT(curCount > INITIAL_STRONG_VALUE, "attemptIncStrong in %p underflowed to INITIAL_STRONG_VALUE", this); if (android_atomic_cmpxchg(curCount, curCount-INITIAL_STRONG_VALUE, &impl->mStrong) == 0) { break; } // the strong-count changed on us, we need to re-assert the situation, // for e.g.: it's possible the fix-up happened in another thread. curCount = impl->mStrong; }