Android智能指针
智能指針的目標
??在使用指針的時候容易出現的問題不外乎下面幾個。首先,指針在使用之前都必須初始化,這個還算容易解決,在創建指針變量的時候同步初始化就好了;第二個問題就是經常忘記delete,就我的經驗來看,這個還是很容易忘記的,在一個大型程序中要是有那么幾個地方忘記執行delete,長久來看系統內存肯定會被消耗完;第三個問題就是就算記得delete,但是也不是說delete就delete的,要是還有別的對象在引用這個對象,然后被delete了,那么在其他地方訪問這個對象的時候程序肯定會奔潰的。
??有了智能指針后,上面的問題就好辦了,首先創建智能指針的時候也同時創建需要管理的對象,然后將需要管理的對象委托給智能指針來管理就好了。在智能指針內部管理著一個引用計數值,當有新的智能指針引用這個對象時,引用計數值加一,當本來引用該對象的智能指針指向其他對象時,那么引用計數值就減一,當引用計數值減為0的時候就智能指針會幫忙將對象delete,也就解決了忘記delete以及在錯誤時刻進行delete的困境了。這樣上面出現的問題就都能很好的解決了。
輕量級指針
template <class T> class LightRefBase { public:inline LightRefBase() : mCount(0) { }inline void incStrong(__attribute__((unused)) const void* id) const {android_atomic_inc(&mCount);}inline void decStrong(__attribute__((unused)) 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:friend class ReferenceMover;inline static void renameRefs(size_t n, const ReferenceRenamer& renamer) { }inline static void renameRefId(T* ref,const void* old_id, const void* new_id) { }private:mutable volatile int32_t mCount; };??首先看一下輕量級指針,輕量級指針屬于模板類,要想使用輕量級指針的功能只要在創建自身類的時候繼承這個類就OK了,然后在這個類內部組織管理著一個引用計數值。這個值的功能和前面說的一樣,起到控制對象生命周期的作用。incStrong和decStrong起到減少和增加引用計數值的功能。
??因為LightRefBase內沒有用來保存待委托對象的指針,所以LightRefBase不算是智能指針,大概算是指針的升級版本。以這個類作為基類的類還需要搭配真正的智能指針才能發揮作用。之后會介紹真正的智能指針sp和wp。
強指針
sp類
sp類相對簡單,大家看一下代碼的實現基本也能了解,下面會配合Refbase進行簡單的分析。
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();// Assignmentsp& 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);// Resetvoid clear();// Accessorsinline T& operator* () const { return *m_ptr; }inline T* operator-> () const { return m_ptr; }inline T* get() const { return m_ptr; }// OperatorsCOMPARE(==)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; };??強指針使用的引用計數類是RefBase,它比LightRefBase復雜得多,所以后者才會被稱為輕量級指針。下面看一下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 = 0x0001};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);private:friend class ReferenceMover;static void renameRefs(size_t n, const ReferenceRenamer& renamer);static void renameRefId(weakref_type* ref,const void* old_id, const void* new_id);static void renameRefId(RefBase* ref,const void* old_id, const void* new_id);weakref_impl* const mRefs; };??RefBase和LightRefBase一樣提供了incStrong和decStrong成員函數來操作引用計數器;而RefBase和LightRefbase類最大的區別就是它不像LightRefBase那么簡單,只提供一個引用計數器,而是提供了一個強引用計數器和一個弱引用計數器。這兩種計數器的功能是由weakref_impl類的變量mRefs提供的。
weakref_impl類
??RefBase類的成員變量mRefs的類型為weakref_impl指針,這個類的代碼在RefBase.cpp文件內,里面的代碼看似很復雜,其實細心了解下里面有一個DEBUG_REFS宏,這個宏里面的代碼只有在Debug版本下才會去實現,否則為空,所以基本可以不用看。
class RefBase::weakref_impl : public RefBase::weakref_type { public:volatile int32_t mStrong;volatile int32_t mWeak;RefBase* const mBase;volatile int32_t mFlags;#if !DEBUG_REFSweakref_impl(RefBase* base): mStrong(INITIAL_STRONG_VALUE), mWeak(0), mBase(base), mFlags(0){}void addStrongRef(const void* /*id*/) { }void removeStrongRef(const void* /*id*/) { }void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }void addWeakRef(const void* /*id*/) { }void removeWeakRef(const void* /*id*/) { }void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }void printRefs() const { }void trackMe(bool, bool) { }#elseweakref_impl(RefBase* base): mStrong(INITIAL_STRONG_VALUE), mWeak(0), mBase(base), mFlags(0), mStrongRefs(NULL), mWeakRefs(NULL), mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT), mRetain(false){}~weakref_impl(){bool dumpStack = false;if (!mRetain && mStrongRefs != NULL) {dumpStack = true;ALOGE("Strong references remain:");ref_entry* refs = mStrongRefs;while (refs) {char inc = refs->ref >= 0 ? '+' : '-';ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref); #if DEBUG_REFS_CALLSTACK_ENABLEDrefs->stack.log(LOG_TAG); #endifrefs = refs->next;}}if (!mRetain && mWeakRefs != NULL) {dumpStack = true;ALOGE("Weak references remain!");ref_entry* refs = mWeakRefs;while (refs) {char inc = refs->ref >= 0 ? '+' : '-';ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref); #if DEBUG_REFS_CALLSTACK_ENABLEDrefs->stack.log(LOG_TAG); #endifrefs = refs->next;}}if (dumpStack) {ALOGE("above errors at:");CallStack stack(LOG_TAG);}}void addStrongRef(const void* id) {//ALOGD_IF(mTrackEnabled,// "addStrongRef: RefBase=%p, id=%p", mBase, id);addRef(&mStrongRefs, id, mStrong);}void removeStrongRef(const void* id) {//ALOGD_IF(mTrackEnabled,// "removeStrongRef: RefBase=%p, id=%p", mBase, id);if (!mRetain) {removeRef(&mStrongRefs, id);} else {addRef(&mStrongRefs, id, -mStrong);}}………..void addWeakRef(const void* id) {addRef(&mWeakRefs, id, mWeak);}void removeWeakRef(const void* id) {if (!mRetain) {removeRef(&mWeakRefs, id);} else {addRef(&mWeakRefs, id, -mWeak);}}……………private:struct ref_entry{ref_entry* next;const void* id; #if DEBUG_REFS_CALLSTACK_ENABLEDCallStack stack; #endifint32_t ref;};void addRef(ref_entry** refs, const void* id, int32_t mRef){if (mTrackEnabled) {AutoMutex _l(mMutex);ref_entry* ref = new ref_entry;// Reference count at the time of the snapshot, but before the// update. Positive value means we increment, negative--we// decrement the reference count.ref->ref = mRef;ref->id = id; #if DEBUG_REFS_CALLSTACK_ENABLEDref->stack.update(2); #endifref->next = *refs;*refs = ref;}}void removeRef(ref_entry** refs, const void* id){if (mTrackEnabled) {AutoMutex _l(mMutex);ref_entry* const head = *refs;ref_entry* ref = head;while (ref != NULL) {if (ref->id == id) {*refs = ref->next;delete ref;return;}refs = &ref->next;ref = *refs;}ALOGE("RefBase: removing id %p on RefBase %p""(weakref_type %p) that doesn't exist!",id, mBase, this);ref = head;while (ref) {char inc = ref->ref >= 0 ? '+' : '-';ALOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);ref = ref->next;}CallStack stack(LOG_TAG);}}…..…..mutable Mutex mMutex;ref_entry* mStrongRefs;ref_entry* mWeakRefs;bool mTrackEnabled;// Collect stack traces on addref and removeref, instead of deleting the stack references// on removeref that match the address ones.bool mRetain;#endif };Weakref_impl類是weakref_base的子類,這個是接口與實現分離的思想。
RefBase的incStrong函數
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); }??這里的other就是實際的對象,這個對象可以是繼承了LightRefBase的對象也可以是繼承了RefBase的對象,因為這里主要分析RefBase對象,所以這里以及下面的內容都假設other對象是繼承了RefBase的內容的,下面看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);ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs); #if PRINT_REFSALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c); #endifif (c != INITIAL_STRONG_VALUE) {return;}android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);refs->mBase->onFirstRef(); }其中mRefs實在RefBase的構造函數中創建的
RefBase::RefBase(): mRefs(new weakref_impl(this)) { }重新回到incStrong函數中,我們會發現這個函數中其實只是做了三件事情:
- 增加弱引用計數?refs->incWeak(id);
- 增加強引用計數?const int32_t c = android_atomic_inc(&refs->mStrong);
- 如果發現是第一次調用對象的incStrong,那么就會修正mStrong引用計數,然后調用這個對象的onFirstRef函數
??在調用weakref_impl的構造函數的時候會將mStrong的值初始化為INITIAL_STRONG_VALUE=1<<28;那么在執行加1操作后,mStrong就等于1<<28+1;返回的值c等于加1前的值,即1<<28;所以第一次調用incStrong后需要對mStrong的值進行修正,加上-INITIAL_STRONG_VALUE正好。
??現在回頭看增加弱引用計數的代碼,通過調用weakref_impl的incWeak來對弱引用計數進行加1操作,而weakref_impl類的incWeak則是直接從父類weakref_base中繼承來的。
void RefBase::weakref_type::incWeak(const void* id) {weakref_impl* const impl = static_cast<weakref_impl*>(this);impl->addWeakRef(id);const int32_t c __unused = android_atomic_inc(&impl->mWeak);ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this); }上面代碼增加弱引用計數主要是執行android_atomic_inc方法來完成的。
RefBase的decStrong函數
template<typename T> sp<T>::~sp() {if (m_ptr)m_ptr->decStrong(this); }上面的代碼調用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 PRINT_REFSALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c); #endifALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);if (c == 1) {refs->mBase->onLastStrongRef(id);if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {delete this;}}refs->decWeak(id); }??上面代碼先將強引用計數減1,如果發現返回值為1的話,就代表調用此時強引用計數值已經為0了,那么就調用onLastStrongRef函數,這個函數在RefBase中的實現也是為空的,一般是留給子類來實現。然后判斷mask是否為OBJECT_LISTTIME_STRONG,如果是,代表該對象的生命周期受強引用計數值控制,當這個對象的強引用計數值為0時,就將這個對象delete掉。
??對弱引用計數值的操作則是調用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);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.// 刪除impl該對象delete impl->mBase;} else {// ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);// 這種時對象被強引用過了,所以只需要直接刪除impl即可delete impl;}} 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;}} }在這個函數中,當弱引用計數不為1則直接return,如果為1那么減1后就為0了,需要對對象進行delete操作。而弱引用計數為1又分為兩種情況:
??第一種情況為對象的生命周期只受強引用控制,而當強引用計數為初始值的時候,就要刪除impl->mBase就是刪除實際的對象。而RefBase被刪除的時候就會調用析構函數,而在析構函數中決定是否需要將mRefs刪除。
當時如果強引用指數不為初始值的時候,就直接調用delete impl,那是因為在decStrong函數中就已經將實際的對象delete掉了。
??第二種情況,當對象的生命周期不受強引用控制時,先調用onLastWeakRef函數,然后如果對象的生命周期時由弱引用控制,就直接刪除RefBase對象,當然在RefBase的析構函數中也會刪除mRefs對象。
弱指針
wp類
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();// Assignmentwp& 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 spsp<T> promote() const;// Resetvoid clear();// Accessorsinline weakref_type* get_refs() const { return m_refs; }inline T* unsafe_get() const { return m_ptr; }// OperatorsCOMPARE_WEAK(==)COMPARE_WEAK(!=)COMPARE_WEAK(>)COMPARE_WEAK(<)COMPARE_WEAK(<=)COMPARE_WEAK(>=)inline bool operator == (const wp<T>& o) const {return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);}template<typename U>inline bool operator == (const wp<U>& o) const {return m_ptr == o.m_ptr;}inline bool operator > (const wp<T>& o) const {return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);}template<typename U>inline bool operator > (const wp<U>& o) const {return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);}inline bool operator < (const wp<T>& o) const {return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);}template<typename U>inline bool operator < (const wp<U>& o) const {return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);}inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }inline bool operator <= (const wp<T>& o) const { return !operator > (o); }template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }inline bool operator >= (const wp<T>& o) const { return !operator < (o); }template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }private:template<typename Y> friend class sp;template<typename Y> friend class wp;T* m_ptr;weakref_type* m_refs; };??與強指針類相比,他們都有一個成員變量m_ptr指向目標對象,但是弱指針還有一個額外的成員變量m_refs,他的類型時weakref_type指針,下面我們分析弱指針的構造函數時再看看他是如何初始化的。這里我們需要關注的是構造函數和析構函數。
wp類的構造函數
先看看wp類的構造函數
template<typename T> wp<T>::wp(T* other): m_ptr(other) {if (other) m_refs = other->createWeak(this); }??這里調用RefBase的createWeak函數,返回值為m_refs。
??在RefBase的createWeak函數中,直接調用weakref_impl的incWeak函數,這個函數之前分析過了就是增加弱引用計數的,同時返回mRefs給調用函數。
RefBase::weakref_type* RefBase::createWeak(const void* id) const {mRefs->incWeak(id);return mRefs; }??接下分析析構函數,這里直接調用weakref_impl的decWeak函數,前面分析過這個函數了。在這個函數里面弱引用次數減1,然后決定是否需要delete impl等。
template<typename T> wp<T>::~wp() {if (m_ptr) m_refs->decWeak(this); }升級為強指針
??分析到這里,弱指針還沒有分析完成,這里面還有一個非常重要的特性還沒有分析,那就是將弱指針升級為強指針的操作,是直接調用其中的promote函數
template<typename T> sp<T> wp<T>::promote() const {sp result;if (m_ptr && m_refs->attemptIncStrong(&result)) {result.set_pointer(m_ptr);}return result; } http://blog4jimmy.com/2018/01/324.htmlhttp://blog4jimmy.com/2018/01/324.html
總結
以上是生活随笔為你收集整理的Android智能指针的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android上超级好用的前端调试方法(
- 下一篇: Android Zygote分析