3 | : mRefs( new weakref_impl( this )) |
4. 强引用计数和弱引用计数
在讨论智能指针前我们先考虑这样一种情况。假设A对象是由MA模块来创建和销毁的,MB模块的B对象增加A对象的引用计数来使用A对象,有一种情况 是:MA模块比MB模块提前被销毁,由于B对象使用着A,A的引用计数不为0,则A不会被销毁。在MA销毁后B继续使用A,假设A使用了MA模块的其他对 象或者资源,这时就会出问题,因为MA模块的其他对象或者资源已经销毁了。
为了解决上述问题,引用计数细分为强引用计数和弱引用计数。一般情况下,强引用计数控制着对象生命周期,如果强引用计数减为0时目标对象自动析构,即使弱引用计数不为0。弱引用计数后面介绍。
5. sp和wp
前面说过,智能指针管理着对象的引用计数,Android中智能指针的实现是sp和wp。sp是strong pointer,wp是weak pointer。sp增加引用计数会分别将强引用计数和弱引用计数+1,wp增加引用计数时只会讲弱引用计数+1,。因此,弱引用计数总是 >= 强引用计数。sp可以保证目标对象一直是有效的,但wp不能保证,因此wp不能直接调用目标对象的方法,wp需要提升为sp后才能调用目标对象的方法。所 以wp没有提供指针操作符重载方法(operator* ()和operator->)。
sp和wp分别定义在
frameworks/base/include/utils/StrongPointer.h和frameworks/base/include/utils/RefBase.h文件。
sp对象构造调用incStrong
09 | if (other) other->incStrong( this ); |
incStrong将mStrong和mWeak分别加1,mStrong的值从INITIAL_STRONG_VALUE改为1
01 | void RefBase::incStrong( const void * id) const |
03 | weakref_impl* const refs = mRefs; |
05 | const int32_t c = android_atomic_inc(&refs->mStrong); |
07 | if (c != INITIAL_STRONG_VALUE) { |
11 | android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); |
sp对象析构调用decStrong
4 | if (m_ptr) m_ptr->decStrong( this ); |
decStrong分别将mStrong和mWeak 减1,mStrong减为0时。如果mFlags的OBJECT_LIFETIME_STRONG被设置,调用delete this;析构目标对象。OBJECT_LIFETIME_STRONG是默认的情况,后面讨论。
01 | void RefBase::decStrong( const void * id) const |
04 | const int32_t c = android_atomic_dec(&refs->mStrong); |
08 | if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { |
wp对象的构造和析构过程也是类似的,构造时mWeak加1,析构时mWeak减1
6. wp提升为sp的过程
wp对象调用promote方法返回sp对象,如果sp指向的对象已经销毁,promote返回NULL
2 | sp<T> wp<T>::promote() const |
5 | if (m_ptr && m_refs->attemptIncStrong(&result)) { |
6 | result.set_pointer(m_ptr); |
可以将wp提升为sp的三种情况:
1、 没有sp指向目标对象且mStrong == INITIAL_STRONG_VALUE
2、 没有sp指向目标对象且mStrong == 0 且mFlags == OBJECT_LIFETIME_WEAK
3、有sp指向目标对象
attemptIncStrong()代码说明了上面的三种情况
01 | bool RefBase::weakref_type::attemptIncStrong( const void * id) |
07 | weakref_impl* const impl = static_cast <weakref_impl*>( this ); |
09 | int32_t curCount = impl->mStrong; |
11 | LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow" , |
15 | while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) { |
17 | if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) { |
23 | curCount = impl->mStrong; |
27 | if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) { |
31 | if (curCount == INITIAL_STRONG_VALUE) { |
41 | allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK |
43 | || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id); |
55 | allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK |
57 | && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id); |
64 | curCount = android_atomic_inc(&impl->mStrong); |