Android指針管理:RefBase,SP,WP


Android中經過引用計數來實現智能指針,而且實現有強指針與弱指針。由對象自己來提供引用計數器,可是對象不會去維護引用計數器的值,而是由智能指針來管理。html

要達到全部對象均可用引用計數器實現智能指針管理的目標,能夠定義一個公共類,提供引用計數的方法,全部對象都去繼承這個公共類,這樣就能夠實現全部對象均可以用引用計數來管理的目標,在Android中,這個公共類就是RefBase,同時還有一個簡單版本LightRefBase。android

RefBase做爲公共基類提供了引用計數的方法,可是並不去維護引用計數的值,而是由兩個智能指針來進行管理:sp(Strong Pointer)和wp(Weak Pointer),表明強引用計數和弱引用計數。 app

1、輕量級引用計數的實現:LightRefBase

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;
};
 

2、sp(Strong Pointer)

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掉。

3、RefBase

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
  1. 若是判斷爲true表示對象只被弱引用引用過,如今弱引用數爲0,直接刪除實際對象。

  2. 若是判斷爲false,表示對象曾經被強引用引用過,但如今強引用爲變爲0了(由於增長或減少強引用數時必定同時增長或減少弱引用數,因此弱引用數爲0時,強引用數必定爲0),弱引用數爲0了,直接釋放mRefs,而實際對象因爲受強引用數控制,已經在RefBase::decStrong中被delete了。

若判斷結果爲false:

    判斷mFlgs是不是OBJECT_LIFETIME_FOREVER,若是是,什麼都不做由用戶本身控制對象的生命週期,不然,實際對象的生命週期受弱引用數控制,如今弱引用數爲0,delete實際對象。

4、wp(Weak Pointer)

定義以下:

 
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函數。

5、總結

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

相關文章
相關標籤/搜索