android智能指针学习

原创 2013年12月02日 17:31:16

代码来源:android4.2.2源码

智能指针参考原型:<c++ primer>13章 复制控制->13.5 用引用计数法来定义智能指针。

android智能指针类文件:RefBase.h,StrongPointer.h

定义了两个计数类和两种智能指针。两种计数类分别是轻量级计数(LightRefBase)和强弱引用计数类RefBase。两种智能指针分别是强指针模版类(sp)和弱指针模版类(wp)。

1. 轻量级计数类(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:
    friend class ReferenceMover;
    inline static void moveReferences(void* d, void const* s, size_t n,
            const ReferenceConverterBase& caster) { }
private:
    mutable volatile int32_t mCount;
};

轻量级计数类仅有一个成员变量mCount用来保存引用计数。提供接口incStrong和decStrong来维护引用计数,当引用计数减为0时,就会释放对象。


2. 强弱指针计数类(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() // 策略枚举,当mFlags为0时,强指针计数减为0则释放。当mFlags为1时,仅当弱指针减为0时释放。默认为0.
    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 ReferenceMover;
    static void moveReferences(void* d, void const* s, size_t n,
            const ReferenceConverterBase& caster);
private:
    friend class weakref_type;
    class weakref_impl;
                            RefBase(const RefBase& o);
            RefBase&        operator=(const RefBase& o);
        weakref_impl* const mRefs; // 保存引用计数
}
RefBase比LightRefBase要复杂,不是用一个整型成员变量来保存计数,而是由mRefs来保存计数。

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_REFS
    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 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) { }
mRefs有四个成员,分别是强指针计数,弱指针计数,RefBase引用和mFlags(策略标准)。weakref_impl在非调试时方法均为空,忽略不计。后面结合智能指针再具体介绍RefBase的实现。


3. 强指针(sp)

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;
};
强指针是一个模版类,参数必须实现RefBase或LightRefBase(轻量级计数类实现强指针计数功能)。它有一个成员变量m_ptr,指向实际的对象。我们仅关注构造函数,复制,赋值和析构这些会改变计数器的方法的实现。以复制构造函数为例:

template<typename T>
sp<T>::sp(const sp<T>& other)
: m_ptr(other.m_ptr)
  {
    if (m_ptr) m_ptr->incStrong(this);
  }
主要有两个工作:1)m_ptr指向具体的对象。2)增加强指针引用计数。

如果是LightRefBase计数,直接增加mCount计数值。这里主要讨论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_REFS
    ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    if (c != INITIAL_STRONG_VALUE)  {
        return;
    }

    android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
    refs->mBase->onFirstRef();
}
这个函数做了三件事情:1)增加弱引用计数。2)增加强引用计数。3)如果是首次调用,则调用onFirstRef,提供这个接口供首次调用做一些处理。

    impl->addWeakRef(id); // incWeak调用
    const int32_t c = android_atomic_inc(&impl->mWeak);

    refs->addStrongRef(id);
    const int32_t c = android_atomic_inc(&refs->mStrong);
这里的调用addWeakRef和addStrongRef仅仅方便调试使用,在非调试时为空实现。实际的增加强弱引用计数为android_atomic_inc。


再看看强指针的析构函数:

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_REFS
    ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    ALOG_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) { // 如果mFlags为0,则在强引用减为0时释放。
            delete this;
        }
    }
    refs->decWeak(id); // 减少弱引用计数,实现如下
}
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) { // 如果mFlags为0,且incStrong没有调用过,就释放对象
            // Special case: we never had a strong reference, so we need to
            // destroy the object now.
            delete impl->mBase;
        } else {   // 否则mFlags为0时,在decStrong中已经释放,这里只需要释放mRefs。
            // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
            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) { // 当mFlags为1时,弱引用计数减为0时释放。
            // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
            // is gone, we can destroy the object.
            delete impl->mBase;
        }
    }
}
总结:

1). 强指针在增加强引用的同时也会增加弱引用计数。因此有弱引用计数>=强引用计数(强引用初始值除外)

2). 如果mFlags设为0(OBJECT_LIFETIME_STRONG),当强引用计数减为0时则释放对象。

3). 如果mFlags设为1(OBJECT_LIFETIME_WEAK),则生命周期依赖于弱引用,当弱引用减为0时释放对象。


4. 弱指针(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();
    // 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_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;
};
弱指针也是一个模版类,参数必须实现RefBase。除了有一个成员变量m_ptr指向实际的对象外,还有一个m_refs成员。这个m_refs指向的是模版类参数RefBase类的mRefs。从弱指针的构造函数中就能够看出来:

template<typename T>
wp<T>::wp(const sp<T>& other)
    : m_ptr(other.m_ptr)
{
    if (m_ptr) {
        m_refs = m_ptr->createWeak(this);
    }
}
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
    mRefs->incWeak(id);
    return mRefs;
}
这里的incWeak前面已经分析过,增加弱引用计数,返回的是RefBase的成员mRefs。

析构函数:

template<typename T>
wp<T>::~wp()
{
    if (m_ptr) m_refs->decWeak(this); // 减少弱引用计数。同上
}
弱引用计数减为0时,释放对象。

总结:

1)弱指针只增加弱引用计数。

2)如果mFlags设为1,则当弱引用计数减为0时释放对象。

差异分析:

弱指针中有个promote函数,来看看它起什么作用。另外要注意到弱引用中并没有重载访问操作符

    // Accessors
    inline  T&      operator* () const  { return *m_ptr; }
    inline  T*      operator-> () const { return m_ptr;  }
    inline  T*      get() const         { return m_ptr; }
没有访问操作符那如何使用弱指针,要使用弱指针时,需使用promote来将弱指针转化为强指针。

template<typename T>
sp<T> wp<T>::promote() const
{
    sp<T> result;
    if (m_ptr && m_refs->attemptIncStrong(&result)) {
        result.set_pointer(m_ptr); // result是一个强指针,如果转换成功,则将强指针的m_ptr设置为弱指针的m_ptr,这样就得到了一个指向同一个对象的一个强指针。
    }
    return result;
}
转化过程并不总是成功的,具体实现在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;
    ALOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
               this);
    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {// 如果强引用大于0,且不为初始值,说明有强指针指向目标对象,直接将强引用计数加1即可。
        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) { // 强引用计数从未增加过,若mFlags为0,则肯定不会被释放。
            // 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 { // 强引用为0,仅当生命周期被弱引用计数控制时才未被释放。
            // 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->addStrongRef(id);

#if PRINT_REFS
    ALOGD("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;
}
尝试增加强引用计数请参考代码中的注释。


到这里,android基本工具智能指针类就分析完毕。

参考:4.2.2源码,老罗博客,android深入理解












版权声明:本文为博主原创文章,未经博主允许不得转载。

Android智能指针学习笔记

1.强指针支持指向两种超类型的引用对象,一种是轻量级引用对象,继承自LightRefBase,另一种姑且称之为重量级引用对象,继承自RefBase。 2.弱指针只支持指向重量级引用对象,继承自RefB...

android中的智能指针案例

  • 2016年05月03日 16:35
  • 9KB
  • 下载

Android 智能指针

Android系统的运行时库层代码是用C++来编写的,用C++来写代码最容易出错的地方就是指针了,一旦使用不当,轻则造成内存泄漏,重则造成系统崩溃。不过系统为我们提供了智能指针,避免出现上述问题,本文...

React Native 4 for Android源码分析 一《JNI智能指针之介绍篇》

文/ Tamic: http://blog.csdn.net/sk719887916/article/details/53455441 原文:http://blog.csdn.net/eewolf/...

Android中的智能指针:sp和wp

原文: Android中的sp和wp指针 链接:http://blog.csdn.net/DroidPhone/article/details/5799792 经常会在android的fr...

Android4.4 智能指针(RefBase, WP, SP)

1: 概述 智能指针的终极目标:  方便开发人员编写代码并且开发人员不必手动维护对象的生命周期。 示例: 1: 未使用智能指针的代码, 当New 出来一个对象的时候(对象保存在Hea...

Android智能指针浅析(win32 debug)

Android智能指针浅析(win32 debug) ============= 目录结构:=========== (一)引言 (二)摘录class RefBase的定义 (三)摘录class R...

Android的智能指针

 在Android的源代码中,经常会看到形如:sp、wp这样的类型定义,这其实是Android 中的智能 指针。智能指针是C++ 中的一个概念,通过基于引用计数的方法,解决对象的自动释放的问题。在...
  • zjc0888
  • zjc0888
  • 2011年04月02日 14:07
  • 521

ReactNative4Android源码分析2: JNI智能指针之实现篇

上一篇介绍了JNI智能指针与wrapper class的作用,下面将对它们的具体实现进行分析,并解答上篇提出的几个问题。       前文回顾了java object在JNI中的引用对象jobject...
  • eewolf
  • eewolf
  • 2016年11月23日 16:57
  • 791
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:android智能指针学习
举报原因:
原因补充:

(最多只允许输入30个字)