Android 智能指针详解 -- RefBase

来源:互联网 发布:java web统计登录次数 编辑:程序博客网 时间:2024/05/03 12:51

来源:

http://blog.csdn.net/shift_wwx/article/details/78864099


前言:

关于android 智能指针,前面详细分析了sp 和 wp的source code,但是还有一些疑问,在这一篇中全部解释,因为所有的源头都是来自于这里。

更多信息可以看 sp的博文 和 wp的博文


本文总结基于Android 7.0


source code:

system/core/include/utils/RefBase.h

system/core/include/libutils/RefBase.cpp


可能最开始有人注意到,sp 和 wp都是模板类,模板参数是T 或者是U,构造函数或者重载运算符的函数中形参看到的是T * 、 U *,或者是sp<T> &、wp<T> &,完全没有看出来跟RefBase 有什么关系。但是,看完Android 中使用sp 和 wp的地方就知道,传进来的模板参数都是继承自RefBase,所谓的指针类型都是基于这个类。

例如:

class MediaPlayer : public BnMediaPlayerClient,                    public virtual IMediaDeathNotifier{public:    MediaPlayer();    ~MediaPlayer();            void            died();            void            disconnect();
父类是BnMediaPlayerClient 和 IMediaDeathNotifier,
class IMediaDeathNotifier: virtual public RefBase{public:    IMediaDeathNotifier() { addObitRecipient(this); }    virtual ~IMediaDeathNotifier() { removeObitRecipient(this); }
随便找个,可以看到是继承RefBase,注意的是虚拟继承。

注意,有可能后面会有很多类继承自RefBase,为了避免继承二义性,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    = 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;};
1、在sp 中看到的指针m_ptr都是通过incStrong 和decStrong 来控制计数,最终调用的就是这里的

2、在wp 中的m_refs的类型是weakref_type类型的指针,在这里也能看到了

所以对于wp中的指针来说,确切的说是RefBase类型的指针,只能调用createWeak,而incWeak和decWeak是weakref_type的对象才能调用。

这就解释了 wp博文 中遗留问题的第 1 、2
3、RefBase的关键是mRefs,类型为weakref_impl *,这个是整个智能指针的关键


下面来详细看下RefBase的实现,首先来看下RefBase的构造函数:

RefBase::RefBase()    : mRefs(new weakref_impl(this)){}
只有一个默认的构造函数,就是为了初始化mRefs,也就是说,以后RefBase的派生类在构造的时候,都会有个mRefs的指针变量。

来看下核心变量mRefs的类型weakref_impl:

class RefBase::weakref_impl : public RefBase::weakref_type{public:    std::atomic<int32_t>    mStrong; //对于强引用计数控制是通过这个变量    std::atomic<int32_t>    mWeak; //对于弱引用的计数控制是通过这个变量    RefBase* const          mBase; //当前指针的标志,以后可能有很多对该指针引用,但是这个mBase只有一个    std::atomic<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) { }#else    weakref_impl(RefBase* base) //构造函数        : mStrong(INITIAL_STRONG_VALUE) //默认强引用计数为1<<28        , mWeak(0) //默认弱引用的计数为0        , mBase(base) //RefBase,也就是后来的指针,注意,后来weakref_impl需要delete的时候,这里mBase 也需要delete,具体看decWeak        , 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_ENABLED                refs->stack.log(LOG_TAG);#endif                refs = 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_ENABLED                refs->stack.log(LOG_TAG);#endif                refs = refs->next;            }        }        if (dumpStack) {            ALOGE("above errors at:");            CallStack stack(LOG_TAG);        }    }    void addStrongRef(const void* id) { //强引用的指针地址会做为id存放在mStrongRefs链表中        //ALOGD_IF(mTrackEnabled,        //        "addStrongRef: RefBase=%p, id=%p", mBase, id);        addRef(&mStrongRefs, id, mStrong.load(std::memory_order_relaxed));    }    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.load(std::memory_order_relaxed));        }    }    void renameStrongRefId(const void* old_id, const void* new_id) {        //ALOGD_IF(mTrackEnabled,        //        "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",        //        mBase, old_id, new_id);        renameRefsId(mStrongRefs, old_id, new_id);    }    void addWeakRef(const void* id) { //将弱引用的指针作为id存放链表mWeakRefs中        addRef(&mWeakRefs, id, mWeak.load(std::memory_order_relaxed));    }    void removeWeakRef(const void* id) {        if (!mRetain) {            removeRef(&mWeakRefs, id);        } else {            addRef(&mWeakRefs, id, -mWeak.load(std::memory_order_relaxed));        }    }    void renameWeakRefId(const void* old_id, const void* new_id) {        renameRefsId(mWeakRefs, old_id, new_id);    }    void trackMe(bool track, bool retain)    {         mTrackEnabled = track;        mRetain = retain;    }    void printRefs() const //打印该指针的所有引用    {        String8 text;        {            Mutex::Autolock _l(mMutex);            char buf[128];            sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);            text.append(buf);            printRefsLocked(&text, mStrongRefs);            sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);            text.append(buf);            printRefsLocked(&text, mWeakRefs);        }        {            char name[100];            snprintf(name, 100, DEBUG_REFS_CALLSTACK_PATH "/%p.stack", this);            int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);            if (rc >= 0) {                write(rc, text.string(), text.length());                close(rc);                ALOGD("STACK TRACE for %p saved in %s", this, name);            }            else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,                      name, strerror(errno));        }    }private:    struct ref_entry //链表结构体,单项链表    {        ref_entry* next;        const void* id;#if DEBUG_REFS_CALLSTACK_ENABLED        CallStack stack;#endif        int32_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_ENABLED            ref->stack.update(2);#endif            ref->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);        }    }    void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)    {        if (mTrackEnabled) {            AutoMutex _l(mMutex);            ref_entry* ref = r;            while (ref != NULL) {                if (ref->id == old_id) {                    ref->id = new_id;                }                ref = ref->next;            }        }    }    void printRefsLocked(String8* out, const ref_entry* refs) const    {        char buf[128];        while (refs) {            char inc = refs->ref >= 0 ? '+' : '-';            sprintf(buf, "\t%c ID %p (ref %d):\n",                     inc, refs->id, refs->ref);            out->append(buf);#if DEBUG_REFS_CALLSTACK_ENABLED            out->append(refs->stack.toString("\t\t"));#else            out->append("\t\t(call stacks disabled)");#endif            refs = refs->next;        }    }    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};


再来看下incWeak():

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 = impl->mWeak.fetch_add(1,            std::memory_order_relaxed); //计数加1    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);}
其中addWeakRef():

    void addWeakRef(const void* id) {        addRef(&mWeakRefs, id, mWeak.load(std::memory_order_relaxed));    }
添加弱引用到链表。

再来看下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 = impl->mWeak.fetch_sub(1, std::memory_order_release); //计数减1    ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);    if (c != 1) return; //还有其他引用在用这个指针,直接返回    atomic_thread_fence(std::memory_order_acquire);    int32_t flags = impl->mFlags.load(std::memory_order_relaxed);    if ((flags&OBJECT_LIFETIME_MASK) == 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.load(std::memory_order_relaxed)                == INITIAL_STRONG_VALUE) {            // Special case: we never had a strong reference, so we need to            // destroy the object now.            delete impl->mBase; //如果没有其他的引用了,需要释放当前指针        } else {            // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);            delete impl;        }    } else {        // This is the OBJECT_LIFETIME_WEAK case. The last weak-reference        // is gone, we can destroy the object.        impl->mBase->onLastWeakRef(id);        delete impl->mBase; //如果没有其他引用了,就释放当前指针    }}

再来看下incStrong():

void RefBase::incStrong(const void* id) const{    weakref_impl* const refs = mRefs;    refs->incWeak(id); //原来强引用也会添加弱引用链表        refs->addStrongRef(id); //添加强引用链表    const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);    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;    }    int32_t old = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,            std::memory_order_relaxed);    // A decStrong() must still happen after us.    ALOG_ASSERT(old > INITIAL_STRONG_VALUE, "0x%x too small", old);    refs->mBase->onFirstRef(); //第一次添加需要调用onFirstRef()}


再来看下decStrong():

void RefBase::decStrong(const void* id) const{    weakref_impl* const refs = mRefs;    refs->removeStrongRef(id);//移除强引用链表中的引用id    const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);//计数减1#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) {//如果是最后一个了,那需要释放该指针了        std::atomic_thread_fence(std::memory_order_acquire);        refs->mBase->onLastStrongRef(id);        int32_t flags = refs->mFlags.load(std::memory_order_relaxed);        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {            delete this;            // Since mStrong had been incremented, the destructor did not            // delete refs.        }    }    // Note that even with only strong reference operations, the thread    // deallocating this may not be the same as the thread deallocating refs.    // That's OK: all accesses to this happen before its deletion here,    // and all accesses to refs happen before its deletion in the final decWeak.    // The destructor can safely access mRefs because either it's deleting    // mRefs itself, or it's running entirely before the final mWeak decrement.    refs->decWeak(id);//如果不是最后一个,需要减少弱引用链表}

这样, wp博文中的第2、4点就解释完了。


小结一下:

1、incStrong和incWeak方法比较简单,就是增加一下强引用和弱引用计数,需要注意的是,incStrong方法中会调用incWeak方法
2、decWeak方法有点复杂,要做的事有两件:是否要释放真实对象,是否要释放影子对象:
1) 如果生命周期是弱引用来控制,那么在这里就需要做判断,弱应用的计数是否为0,是否要释放真实对象和影子对象
2) 如果生命周期是强引用来控制的,那么这里也要判断一下,如果强引用计数为0的话,需要释放真实对象,弱引用计数是否为0,是否要释放影子对象
从这里我们可以看到:
弱引用计数是关系影子对象的,如果弱引用计数为0,那么影子对象一定要释放,但是真实对象不一定要释放
强引用计数是关系真实对象的,如果强引用计数为0,那么真实对象一定要释放的,但是影子对象不一定释放
3、decStrong方法主要做:就是看看是否要释放真实对象,因为强引用和真实对象关联的
4、RefBase的析构方法:真实对象被销毁的时候,需要做一个工作就是释放影子对象
释放影子对象有两个场景:
1) 如果强引用计数根本没有被使用过,那么直接释放
2) 如果强引用计数使用过,但是采用的是非强生命周期管理方式,也是释放


通过RefBase的执行过程,结合wp的构造来看,最终wp中维护的m_ptr并没有使用的地方,而整个过程都是在维护弱引用的链表。

所以,wp如果要使用必须要通过promote函数,转换成sp,再通过sp的重载运算符* 和 运算符 ->来调用指针的成员。

这也就是解释了wp博文中的第 3 点。


android中除了RefBase,还有个轻量级的引用LightRefBase,前面看到的是很多类继承RefBase,后面通过sp、wp实现了只能指针。

如果只是想通过计数方式使用只能指针,也可以用LightRefBase。

先来看下LightRefBase的定义:

template <class T>class LightRefBase{public:    inline LightRefBase() : mCount(0) { }    inline void incStrong(__attribute__((unused)) const void* id) const {        mCount.fetch_add(1, std::memory_order_relaxed);    }    inline void decStrong(__attribute__((unused)) const void* id) const {        if (mCount.fetch_sub(1, std::memory_order_release) == 1) {            std::atomic_thread_fence(std::memory_order_acquire);            delete static_cast<const T*>(this);        }    }    //! DEBUGGING ONLY: Get current strong ref count.    inline int32_t getStrongCount() const {        return mCount.load(std::memory_order_relaxed);    }    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 std::atomic<int32_t> mCount;};
从整个定义来看,就一个核心变量mCount,为什么这里有incStrong、decStrong,就是为了后面使用sp准备。

可以看个例子:

class MyClass : virtual public LightRefBase<MyClass> {public:    void test();};
在main中使用的时候需要通过sp使用:

sp<MyClass> sp(new MyClass());sp->test();


1、LightRefBase 同RefBase一样,必须是某个指针的基类

2、LightRefBase 轻量级引用,采用的是模板机制,而不是复杂的OOP,不需要虚拟继承

3、轻量级引用基类轻在内存,只拥有一个成员变量,用以计数。其引用计数类模板不含有虚函数,如果尾端类(不被其他类继承的类)直接继承引用计数基类,那尾端类也不需要虚的析构函数,不会出现因部分删除而产生内存泄露,因为模板类代码中有一处使用static_cast向下转型,模板确保其安全。

4、RefBase持有弱引用,持有指针,在进行删除工作时较为复杂。


缺陷:

1、不支持弱引用。
2、轻量级引用类,使用模版技术,所以模版技术的缺陷,轻量级引用亦有,很明显一点就是你会需要很多不同轻量级引用类。
3、编译级别支持引用栈对象,运行时会崩溃,Scott Meyers说过只要编译器允许,就一定有人这么干。此问题需要使用者解决-----利用protected dector 和  friend class  refbase



到此,android中只能指针部分就告一段落,后期会在碰到问题继续补充说明。也请大神不吝赐教。


参考:

http://blog.csdn.net/xielinhua88/article/details/51823442

http://blog.csdn.net/zjq2008wd/article/details/17614417

https://www.cnblogs.com/angeldevil/archive/2013/03/10/2952586.html





原创粉丝点击