Android中經過引用計數來實現智能指針,而且實現有強指針與弱指針。由對象自己來提供引用計數器,可是對象不會去維護引用計數器的值,而是由智能指針來管理。html
要達到全部對象均可用引用計數器實現智能指針管理的目標,能夠定義一個公共類,提供引用計數的方法,全部對象都去繼承這個公共類,這樣就能夠實現全部對象均可以用引用計數來管理的目標,在Android中,這個公共類就是RefBase,同時還有一個簡單版本LightRefBase。android
RefBase做爲公共基類提供了引用計數的方法,可是並不去維護引用計數的值,而是由兩個智能指針來進行管理:sp(Strong Pointer)和wp(Weak Pointer),表明強引用計數和弱引用計數。 app
LightRefBase的實現很簡單,只是內部保存了一個變量用於保存對象被引用的次數,並提供了兩個函數用於增長或減小引用計數。函數
template <class T> class LightRefBase { public: inline LightRefBase() : mCount(0) { } inline void incStrong(const void* id) const { android_atomic_inc(&mCount); } inline void decStrong(const void* id) const { if (android_atomic_dec(&mCount) == 1) { delete static_cast<const T*>(this); } } //! DEBUGGING ONLY: Get current strong ref count. inline int32_t getStrongCount() const { return mCount; } typedef LightRefBase<T> basetype; protected: inline ~LightRefBase() { } private: mutable volatile int32_t mCount; };
LightRefBase僅僅提供了引用計數的方法,具體引用數應該怎麼管理,就要經過智能指針類來管理了,每當有一個智能指針指向對象時,對象的引用計數要加1,當一個智能指針取消指向對象時,對象的引用計數要減1,在C++中,當一個對象生成和銷燬時會自動調用(拷貝)構造函數和析構函數,因此,對對象引用數的管理就能夠放到智能指針的(拷貝)構造函數和析構函數中。Android提供了一個智能指針能夠配合LightRefBase使用:sp,sp的定義以下:ui
template <typename T> class sp { public: inline sp() : m_ptr(0) { } sp(T* other); sp(const sp<T>& other); template<typename U> sp(U* other); template<typename U> sp(const sp<U>& other); ~sp(); // Assignment sp& operator = (T* other); sp& operator = (const sp<T>& other); template<typename U> sp& operator = (const sp<U>& other); template<typename U> sp& operator = (U* other); //! Special optimization for use by ProcessState (and nobody else). void force_set(T* other); // Reset void clear(); // Accessors inline T& operator* () const { return *m_ptr; } inline T* operator-> () const { return m_ptr; } inline T* get() const { return m_ptr; } // Operators COMPARE(==) COMPARE(!=) COMPARE(>) COMPARE(<) COMPARE(<=) COMPARE(>=) private: template<typename Y> friend class sp; template<typename Y> friend class wp; void set_pointer(T* ptr); T* m_ptr; };
代碼比較多,其中Accessors部分代碼重載了*、->操做符使咱們使用sp的時候就像使用真實的對象指針同樣,能夠直接操做對象的屬性或方法,COMPARE是宏定義,用於重載關係操做符,因爲對引用計數的控制主要是由(拷貝)構造函數和析構函數控制,因此忽略其餘相關代碼後,sp能夠精簡爲以下形式(賦值操做符也省略掉了,構造函數省略類似的兩個):this
template <typename T> class sp { public: inline sp() : m_ptr(0) { } sp(T* other); sp(const sp<T>& other); ~sp(); private: template<typename Y> friend class sp; template<typename Y> friend class wp; void set_pointer(T* ptr); T* m_ptr; };
默認構造函數使智能指針不指向任何對象,sp(T* other)與sp(
const
sp<T>& other)
的實現以下:atom
template<typename T> sp<T>::sp(T* other) : m_ptr(other) { if (other) other->incStrong(this); } template<typename T> sp<T>::sp(const sp<T>& other) : m_ptr(other.m_ptr) { if (m_ptr) m_ptr->incStrong(this); }
內部變量m_ptr指向實際對象,並調用實際對象的incStrong函數,T繼承自LightRefBase,因此此處調用的是LightRefBase的incStrong函數,以後實際對象的引用計數加1。線程
當智能指針銷燬的時候調用智能指針的析構函數:指針
template<typename T> sp<T>::~sp() { if (m_ptr) m_ptr->decStrong(this); }
調用實際對象即LightRefBase的decStrong函數,其實現以下:調試
inline void decStrong(const void* id) const { if (android_atomic_dec(&mCount) == 1) { delete static_cast<const T*>(this); } }
android_atomic_dec返回mCount減1以前的值,若是返回1表示此次減過以後引用計數就是0了,就把對象delete掉。
RefBase提供了更強大的引用計數的管理。
class RefBase { public: void incStrong(const void* id) const; void decStrong(const void* id) const; void forceIncStrong(const void* id) const; //! DEBUGGING ONLY: Get current strong ref count. int32_t getStrongCount() const; class weakref_type { public: RefBase refBase() const; void incWeak(const void* id); void decWeak(const void* id); // acquires a strong reference if there is already one. bool attemptIncStrong(const void* id); // acquires a weak reference if there is already one. // This is not always safe. see ProcessState.cpp and BpBinder.cpp // for proper use. bool attemptIncWeak(const void* id); //! DEBUGGING ONLY: Get current weak ref count. int32_t getWeakCount() const; //! DEBUGGING ONLY: Print references held on object. void printRefs() const; //! DEBUGGING ONLY: Enable tracking for this object. // enable -- enable/disable tracking // retain -- when tracking is enable, if true, then we save a stack trace // for each reference and dereference; when retain == false, we // match up references and dereferences and keep only the // outstanding ones. void trackMe(bool enable, bool retain); }; weakref_type* createWeak(const void* id) const; weakref_type* getWeakRefs() const; // DEBUGGING ONLY: Print references held on object. inline void printRefs() const { getWeakRefs()->printRefs(); } // DEBUGGING ONLY: Enable tracking of object. inline void trackMe(bool enable, bool retain) { getWeakRefs()->trackMe(enable, retain); } typedef RefBase basetype; protected: RefBase(); virtual ~RefBase(); //! Flags for extendObjectLifetime() enum { OBJECT_LIFETIME_STRONG = 0x0000, OBJECT_LIFETIME_WEAK = 0x0001, OBJECT_LIFETIME_MASK = 0x0003 }; void extendObjectLifetime(int32_t mode); //! Flags for onIncStrongAttempted() enum { FIRST_INC_STRONG = 0x0001 }; virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); virtual bool onIncStrongAttempted(uint32_t flags, const void* id); virtual void onLastWeakRef(const void* id); private: friend class weakref_type; class weakref_impl; RefBase(const RefBase& o); RefBase& operator=(const RefBase& o); weakref_impl* const mRefs; };
不一樣於LightRefBase的是,RefBase內部並無使用一個變量來維護引用計數,而是經過一個weakref_impl *類型的成員來維護引用計數,而且同時提供了強引用計數和弱引用計數。weakref_impl繼承於RefBase::weakref_type,代碼比較多,不過大都是調試代碼,由宏定義分開,Release是不包含調試代碼的,去除這些代碼後其定義爲:
#define INITIAL_STRONG_VALUE (1<<28) class RefBase::weakref_impl : public RefBase::weakref_type { public: volatile int32_t mStrong; volatile int32_t mWeak; RefBase* const mBase; volatile int32_t mFlags; weakref_impl(RefBase* base) : mStrong(INITIAL_STRONG_VALUE) , mWeak(0) , mBase(base) , mFlags(0) { } void addStrongRef(const void* /*id*/) { } void removeStrongRef(const void* /*id*/) { } void addWeakRef(const void* /*id*/) { } void removeWeakRef(const void* /*id*/) { } void printRefs() const { } void trackMe(bool, bool) { } };
weakref_impl中的函數都是做爲調試用,Release版的實現都是空的,成員變量分別表示強引用數、弱引用數、指向實際對象的指針與flag,flag可控制實際對象的生命週期,取值爲0或RefBase中定義的枚舉值。
RefBase提供了incStrong與decStrong函數用於控制強引用計數值,其弱引用計數值是由weakref_impl控制,強引用計數與弱引用數都保存在weakref_impl *類型的成員變量mRefs中。
RefBase同LightRefBase同樣爲對象提供了引用計數的方法,對引用計數的管理一樣要由智能指針控制,因爲RefBase同時實現了強引用計數與弱引用計數,因此就有兩種類型的智能指針,sp(Strong Pointer)與wp(Weak Pointer)。
sp前面已經說過,其(拷貝)構造函數調用對象即RefBase的incStrong函數。
void RefBase::incStrong(const void* id) const { weakref_impl* const refs = mRefs; refs->incWeak(id); refs->addStrongRef(id); const int32_t c = android_atomic_inc(&refs->mStrong); LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs); if (c != INITIAL_STRONG_VALUE) { return; } android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); refs->mBase->onFirstRef(); }
addStrong的函數體爲空,incStrong函數內部首先調用成員變量mRefs的incWeak函數將弱引用數加1,而後再將強引用數加1,因爲android_atomic_inc返回變量的舊值,因此若是其不等於INITIAL_STRONG_VALUE就直接返回,則則是第一次由強智能指針(sp)引用,將其減去INITIAL_STRONG_VALUE後變成1,而後調用對象的onFirstRef。
成員變量mRefs是在對象的構造函數中初始化的:
RefBase::RefBase() : mRefs(new weakref_impl(this)) { }
weakrel_impl的incWeak繼承自父類weakrel_type的incWeak:
void RefBase::weakref_type::incWeak(const void* id) { weakref_impl* const impl = static_cast<weakref_impl*> impl->addWeakRef(id); const int32_t c = android_atomic_inc(&impl->mWeak); LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this); }
addWeakRef實現一樣爲空,因此只是將弱引用計數加1。因此當對象被sp引用後,強引用計數與弱引用計數會同時加1。
當sp銷燬時其析構函數調用對象即RefBase的decStrong函數:
void RefBase::decStrong(const void* id) const { weakref_impl* const refs = mRefs; refs->removeStrongRef(id); const int32_t c = android_atomic_dec(&refs->mStrong); if (c == 1) { const_cast<RefBase*>(this)->onLastStrongRef(id); if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { delete this; } } refs->removeWeakRef(id); refs->decWeak(id); }
decStrong中將強引用數與弱引用數同時減1,若是這是最後一個強引用的話,會調用對象的onLastStrongRef,而且判斷成員變量mRefs的成員變量mFlags來決定是否在對象的強引用數爲0時釋放對象。
mFlags能夠爲0或如下兩個枚舉值:
enum { OBJECT_LIFETIME_WEAK = 0x0001, OBJECT_LIFETIME_FOREVER = 0x0003 };
mFlags的值能夠經過extendObjectLifetime函數改變:
void RefBase::extendObjectLifetime(int32_t mode) { android_atomic_or(mode, &mRefs->mFlags); }
OBJECT_LIFETIME_FOREVER包含OBJECT_LIFETIME_WEAK(位運算中其二進制11包含01),因此當
refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
爲true時表示mFlags爲0,實際對象的生命週期受強引用數控制,因此在強引用數爲0時delete this,不然實際對象的生命週期就由弱引用數控制。
再來看decWeak:
void RefBase::weakref_type::decWeak(const void* id) { weakref_impl* const impl = static_cast<weakref_impl*>(this); impl->removeWeakRef(id); const int32_t c = android_atomic_dec(&impl->mWeak); if (c != 1) return; if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { if (impl->mStrong == INITIAL_STRONG_VALUE) delete impl->mBase; else { delete impl; } } else { impl->mBase->onLastWeakRef(id); if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) { delete impl->mBase; } } }
將弱引用數減1,若減1後不爲0直接返回,不然判斷
(impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
若判斷結果爲true:
實際對象生命週期被強引用數控制,接下來判斷:
mpl->mStrong == INITIAL_STRONG_VALUE
若是判斷爲true表示對象只被弱引用引用過,如今弱引用數爲0,直接刪除實際對象。
若是判斷爲false,表示對象曾經被強引用引用過,但如今強引用爲變爲0了(由於增長或減少強引用數時必定同時增長或減少弱引用數,因此弱引用數爲0時,強引用數必定爲0),弱引用數爲0了,直接釋放mRefs,而實際對象因爲受強引用數控制,已經在RefBase::decStrong中被delete了。
若判斷結果爲false:
判斷mFlgs是不是OBJECT_LIFETIME_FOREVER,若是是,什麼都不做由用戶本身控制對象的生命週期,不然,實際對象的生命週期受弱引用數控制,如今弱引用數爲0,delete實際對象。
定義以下:
template <typename T> class wp { public: typedef typename RefBase::weakref_type weakref_type; inline wp() : m_ptr(0) { } wp(T* other); wp(const wp<T>& other); wp(const sp<T>& other); template<typename U> wp(U* other); template<typename U> wp(const sp<U>& other); template<typename U> wp(const wp<U>& other); ~wp(); // Assignment wp& operator = (T* other); wp& operator = (const wp<T>& other); wp& operator = (const sp<T>& other); template<typename U> wp& operator = (U* other); template<typename U> wp& operator = (const wp<U>& other); template<typename U> wp& operator = (const sp<U>& other); void set_object_and_refs(T* other, weakref_type* refs); // promotion to sp sp<T> promote() const; // Reset void clear(); // Accessors inline weakref_type* get_refs() const { return m_refs; } inline T* unsafe_get() const { return m_ptr; } // Operators COMPARE(==) COMPARE(!=) COMPARE(>) COMPARE(<) COMPARE(<=) COMPARE(>=) private: template<typename Y> friend class sp; template<typename Y> friend class wp; T* m_ptr; weakref_type* m_refs; };
同sp同樣,m_ptr指向實際對象,但wp還有一個成員變量m_refs。
template<typename T> wp<T>::wp(T* other) : m_ptr(other) { if (other) m_refs = other->createWeak(this); } template<typename T> wp<T>::wp(const wp<T>& other) : m_ptr(other.m_ptr), m_refs(other.m_refs) { if (m_ptr) m_refs->incWeak(this); } RefBase::weakref_type* RefBase::createWeak(const void* id) const { mRefs->incWeak(id); return mRefs; }
能夠看到,wp的m_refs就是RefBase即實際對象的mRefs。
wp析構的時候減小弱引用計數:
template<typename T> wp<T>::~wp() { if (m_ptr) m_refs->decWeak(this); }
因爲弱指針沒有重載*與->操做符,因此不能直接操做指向的對象,雖然有unsafe_get函數,但像名字所示的,不建議使用,直接使用實際對象指針的話就不必用智能指針了。
由於弱指針不能直接操做對象,因此要想操做對象的話就要將其轉換爲強指針,即wp::promote方法:
template<typename T> sp<T> wp<T>::promote() const { return sp<T>(m_ptr, m_refs); } template<typename T> sp<T>::sp(T* p, weakref_type* refs) : m_ptr((p && refs->attemptIncStrong(this)) ? p : 0) { }
是否能從弱指針生成一個強指針關鍵是看refs->attemptIncStrong,看其定義:
bool RefBase::weakref_type::attemptIncStrong(const void* id) { incWeak(id); weakref_impl* const impl = static_cast<weakref_impl*>(this); int32_t curCount = impl->mStrong; LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow", this); while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) { if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) { break; } curCount = impl->mStrong; } if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) { bool allow; if (curCount == INITIAL_STRONG_VALUE) { // Attempting to acquire first strong reference... this is allowed // if the object does NOT have a longer lifetime (meaning the // implementation doesn't need to see this), or if the implementation // allows it to happen. allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id); } else { // Attempting to revive the object... this is allowed // if the object DOES have a longer lifetime (so we can safely // call the object with only a weak ref) and the implementation // allows it to happen. allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id); } if (!allow) { decWeak(id); return false; } curCount = android_atomic_inc(&impl->mStrong); // 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->addWeakRef(id); impl->addStrongRef(id); #if PRINT_REFS LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount); #endif if (curCount == INITIAL_STRONG_VALUE) { android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong); impl->mBase->onFirstRef(); } return true; }
首先經過incWeak將弱引用數加1(被強指針sp引用會致使強引用數和弱引用數同時加1),而後:
int32_t curCount = impl->mStrong; while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) { if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) { break; } curCount = impl->mStrong; }
若是以前已經有強引用,直接將強引用數加1,android_atomic_cmpxchg表示若是impl->mStrong的值爲curCount,則把impl->mString的值改成curCount+1,此處用while循環是防止其餘線程已經增長了強引用數。
接下來:
if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE)
表示對象目前沒有強引用,這就要判斷對象是否存在了。
若是curCount == INITIAL_STRONG_VALUE,表示對象沒有被sp引用過。接下來判斷:
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
表示:若是對象的生命週期只受強引用控制,對象必定存在,要有強引用才能夠管理對象的釋放,因此必定會容許生成強引用;若是對象的生命週期受弱引用控制,調用對象的onIncStrongAttempted試圖增長強引用,因爲此時在弱引用中,弱引用必定不爲0,對象也必定存在,調用onIncStrongAttempted的意圖是由於類的實現者可能不但願用強引用引用對象。在RefBase中onIncStrongAttempted默認返回true:
bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id) { return (flags&FIRST_INC_STRONG) ? true : false; }
若是curCount <= 0(只會等於0),表示對象強引用數經歷了INITIAL_STRONG_VALUE -->大於0 --> 0,接下來就要判斷:
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
若是對象的生命週期受強引用數控制,那麼因爲曾被sp引用過,如今強引用數又爲0,對象就已經被delete了,因此就不能生成強引用,不然若是對象的生命週期受弱引用數控制,就經過onIncStrongAttempted看類的實現者是否但願當對象的強引用數變爲0時能夠再次被強引用引用。
if (!allow) { decWeak(id); return false; }
若是allow爲false表示不能從弱引用生成強引用,就要調用decWeak將弱引用減1(由於在promote入口先將弱引用加了1),而後返回false表示生成強引用失敗。
if (curCount == INITIAL_STRONG_VALUE) { android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong); impl->mBase->onFirstRef(); }
最後,若是curCount == INITIAL_STRONG_VALUE表示第一次被sp引用,調用對象的onFirstRef函數。
RefBase內部有一個指針指向實際對象,有一個weakref_impl類型的指針保存對象的強/弱引用計數、對象生命週期控制。
sp只有一個成員變量,用來保存實際對象,但這個實際對象內部已包含了weakref_impl *對象用於保存實際對象的引用計數。sp 管理一個對象指針時,對象的強、弱引用數同時加1,sp銷燬時,對象的強、弱引用數同時減1。
wp中有兩個成員變量,一個保存實際對象,另外一個是weakref_impl *對象。wp管理一個對象指針時,對象的弱引用計數加1,wp銷燬時,對象的弱引用計數減1。
weakref_impl中包含一個flag用於決定對象的生命週期是由強引用數控制仍是由弱引用數控制:
當flag爲0時,實際對象的生命週期由強引用數控制,weakref_impl *對象由弱引用數控制。
當flag爲OBJECT_LIFETIME_WEAK時,實際對象的生命週期受弱引用數控制。
當flag爲OBJECT_LIFETIME_FOREVER時,實際對象的生命週期由用戶控制。
能夠用extendObjectLifetime改變flag的值。
原博客連接:http://www.cnblogs.com/angeldevil/archive/2013/03/10/2952586.html