Android 智能指针详解 -- RefBase

源码基于:Android N

相关博文:

Android 智能指针详解

Android 智能指针详解 -- wp 

Android 智能指针详解 -- sp

Android 智能指针详解 -- RefBase

0. 前言

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

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

source code:

system/core/include/utils/RefBase.h

system/core/include/libutils/RefBase.cpp

1. 源码分析

可能最开始有人注意到,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 的派生类都必须要虚拟继承。
 

1.1 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;
};
  • 在sp 中看到的指针m_ptr都是通过incStrong 和decStrong 来控制计数,最终调用的就是这里的
  • 在wp 中的m_refs的类型是weakref_type类型的指针,在这里也能看到了

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

这就解释了  wp博文 中遗留问题的第 1 、2

  • RefBase的关键是mRefs,类型为weakref_impl *,这个是整个智能指针的关键

1.2 RefBase的构造函数

RefBase::RefBase()
    : mRefs(new weakref_impl(this))
{
}

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

1.3 核心变量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
};

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

添加弱引用到链表。

1.5 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; //如果没有其他引用了,就释放当前指针
    }
}

1.6 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()
}

1.7 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.8 总结

a)incStrong和incWeak方法比较简单,就是增加一下强引用和弱引用计数,需要注意的是,incStrong方法中会调用incWeak方法

b)decWeak方法有点复杂,要做的事有两件:是否要释放真实对象,是否要释放影子对象:

  • 如果生命周期是弱引用来控制,那么在这里就需要做判断,弱应用的计数是否为0,是否要释放真实对象和影子对象
  • 如果生命周期是强引用来控制的,那么这里也要判断一下,如果强引用计数为0的话,需要释放真实对象,弱引用计数是否为0,是否要释放影子对象

从这里我们可以看到:

  • 弱引用计数是关系影子对象的,如果弱引用计数为0,那么影子对象一定要释放,但是真实对象不一定要释放;
  • 强引用计数是关系真实对象的,如果强引用计数为0,那么真实对象一定要释放的,但是影子对象不一定释放;

c)decStrong方法主要做:就是看看是否要释放真实对象,因为强引用和真实对象关联的

d)RefBase的析构方法:真实对象被销毁的时候,需要做一个工作就是释放影子对象

释放影子对象有两个场景:

  • 如果强引用计数根本没有被使用过,那么直接释放
  • 如果强引用计数使用过,但是采用的是非强生命周期管理方式,也是释放

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

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

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

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

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

2. 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();

LightRefBase 总结:

  • LightRefBase 同RefBase一样,必须是某个指针的基类
  • LightRefBase 轻量级引用,采用的是模板机制,而不是复杂的OOP,不需要虚拟继承
  • 轻量级引用基类轻在内存,只拥有一个成员变量,用以计数。其引用计数类模板不含有虚函数,如果尾端类(不被其他类继承的类)直接继承引用计数基类,那尾端类也不需要虚的析构函数,不会出现因部分删除而产生内存泄露,因为模板类代码中有一处使用static_cast向下转型,模板确保其安全
  • RefBase持有弱引用,持有指针,在进行删除工作时较为复杂

LightRefBase  缺陷:

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


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

 

 

 相关博文:

Android 智能指针详解

Android 智能指针详解 -- wp 

Android 智能指针详解 -- sp

Android 智能指针详解 -- RefBase

 

 

 

参考:

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

私房菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值