Android智能指针浅析

Posted createchance

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android智能指针浅析相关的知识,希望对你有一定的参考价值。

长久以来,C++中的内存管理问题一直让人头疼,空指针,野指针,内存泄露。。。。。。C++程序员看到这样的问题就是各种头大!这样的问题往往很难解决,尤其是代码架构比较庞大或者复杂的时候。但是同样是面向对象的JAVA语言却没有这个问题,为什么呢?因为java有GC,也就是垃圾回收而C++没有。C++的做法是:程序员必须做到在new一个对象之后当不需要使用它的时候必须delete这个对象。看来很好,没有问题是吧?但是,在实际的项目中,就是会有人忘记去delete这个对象,或者随意delete一个对象,导致依赖这个对象的别的模块发生野指针错误。这几乎是经常发生的,而且是很难避免的。
android中除了framework之上是Java语言写就的,其余native层到kernel之上这部分基本都是C++写成的。Android的这部分代码量还是比较庞大的,那么它是怎么解决上面提到的C++内存问题的呢?为此,android引入了一个”智能指针“的概念,其实这个概念并不是android提出的,这个概念在C++的boost中就有的,google只是拿过来做了一个精简版本罢了。对C++ boost的智能指针感兴趣的可以看这个博客:
http://blog.csdn.net/xt_xiaotian/article/details/5714477
这里我们专注了解android中的智能指针是怎么实现的。Android的智能指针其实是比较复杂的,一时半会也说不清楚,在正式分析android的智能指针代码之前,我们继续上面的C++内存问题探讨。
前面提到,在C++中需要new和delete配对使用,而且是程序员手动显式执行。这对于程序员的要求是很高的,程序员需要知道什么时候new了一个对象,什么时候这个对象肯定是不需要的了然后采取delete它。这似乎有些理想,因为很多情况下不是这样的,有的时候我们new一个对象然后这个对象就是给别的模块使用的,别的模块又是由别的小组或者公司维护的,他们很可能不会及时delete这个对象。那有什么办法可以解决这个问题呢?我们很容易会想到,专门造一个模块,这个模块来关于众多产生的对象,然后同时负责这些对象的销毁。但是,这个方案有一个问题,如果需要产生多个管理模块的情况下,怎么保证多个模块之间的引用是一致的呢?也就是说可能管理模块A持有某个对象的引用,然后某块B也持有这个对象的引用,这样的话这两个模块之间怎么协调这个对象的引用问题呢?这是比较复杂的,也会有很多潜在的问题。那还有什么办法呢?要解决这个问题需要理解一个事情,那就是对象的引用计数问题,这是java的GC实现的基础。所谓引用计数就是这个对象在几个地方被使用了,比如:

Object a = new Object();
Object b = a;

这两行代码中,新new出来的对象有两个引用计数,引用a和引用b同时指向同一块内存空间。那什么时候我们就不需要这个对象了呢?那就是他不需要的时候?这有点像废话,但是事实就是这样,只要当这个对象的引用计数等于0的时候,这个对象就不需要了。这样以来,这个问题就转化为:找到谁对这个对象的引用技术最为清楚?谁最直接了解这个对象的引用计数?对了!答案就是这个对象它自己!!!什么?你要这个对象自己delete自己,听起来有点荒谬,但是android中的智能指针就是这么做的。

LightRefBase

这是个android中给出的一个轻量级的智能指针解决方案,使用的思想就是我们上面分析的思想。为了让对象可以做到自己delete自己,我们需要给所有的对象做一个公共的基类,这个LightRefBase就是这个基类。在分析这个代码之前,我们先看一下,这个东西我们怎么使用,以下是一个使用它的demo:

/*************************************************************************
    > File Name: lightpointer.cpp
    > Author: Baniel Gao
    > Mail: createchance@163.com 
    > Created Time: Fri 22 Apr 2016 03:27:28 PM CST
 ************************************************************************/

#include <stdio.h>
// 包含需要的头文件
#include <utils/RefBase.h>

using namespace android;

// 目标类必须是LightRefBase的子类
class LightClass : public LightRefBase<LightClass>

    public:
        LightClass()
        
            printf("create instance of lightclass. \\n");
        

        virtual ~LightClass()
        
            printf("destory instance of lightclass. \\n");
        
;

int main(int argc, char** argv)

    // new一个对象,并且将指针指向它
    LightClass* ptr = new LightClass();

    // 打印引用计数,就是看看有多少个地方使用了它,当然这里还没有显式引用,结果应该是0.
    printf("1. Light ref count: %d. \\n", ptr->getStrongCount());
    // sp<>这样的引用就是显式引用,是的一个指针指向它,然后我们看下现在的引用计数是多少
    // 按照推理,应该是1.
    sp<LightClass> ptrOut = ptr;
    printf("2. Light ref count: %d. \\n", ptr->getStrongCount());

    // 代码块,在代码块内部再弄一个指针指向这个对象,然后再看一下引用计数
    
        sp<LightClass> ptrInner = ptr;
        printf("3. Light ref count: %d. \\n", ptr->getStrongCount());
    

    // 再代码块的外面,我们看一下引用计数。由于在代码块的外面,代码块的内部的那个
    // 指向指针应该不存在了,所有引用计数应该比代码块内部少一个。
    printf("4. Light ref count: %d. \\n", ptr->getStrongCount());

    // 将最后一个引用置空, 并且睡眠两秒,等待看看这个对象会不会自动销毁。
    ptrOut = NULL;
    printf("5. Light ref count: %d. \\n", ptr->getStrongCount());

    printf("Wre are going to sleep. \\n");
    sleep(2// 2s后我们直接退出程序
    printf("Wre are going to exit. \\n");
    return 0;

大家先不用管具体的代码细节是怎么回事,先看看运行的结果。为了运行这个程序我们需要编译它,这里我把它编译成android手机上可以运行的二进制文件,下面是Android.mk文件:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_MODULE := lightpointer

LOCAL_SRC_FILES := lightpointer.cpp

LOCAL_SHARED_LIBRAIES :=    \\
    libcutils   \\
    libutils

include $(BUILD_EXECUTABLE)

可执行文件名称就是lightpointer,并且存放于手机的system/bin下,以下是运行效果:

可以看到和我们的猜想是基本一致的。首先,我们new一个对象,但是没有显式引用所以引用计数当然是0,然后我们使用sp类(这个类先不去理会稍后分析)引用它,然后它的计数就是1了,再然后再代码块中再次引用它,发现计数是2,然后在代码块的外部发现对象引用计数还是1,因为代码块执行完毕了,刚才内部的那个指针不存在了。最后我们再把最后一个指针置空,然后这个对象由于引用计数为0了就自动销毁了。看到了没有,是不是有点JAVA的意思啊?使用很简单是不?
现在我们来分析一下刚才代码再android系统内发生了什么,首先我们看一下LightRefBase这个类,代码路径:/system/core/include/utils/RefBase.h
它的代码如下

我们看到,这个类的实现还是比较简答的,整体上公共方法就3个:
incStrong
decStrong
getStrongCount //刚才我们一直在用的方法
我们所有的目标类都应该是它的子类,首先我们应该看一下它的构造器。它的构造器是比较简单的,只是将mCount这个变量初始化为0,从字面意思我们也可以看出这个变量就是表示实际的引用数目。并且我们刚才一直使用的getStrongCount方法也就是把它直接return了。接下来我们看到incStrong和decStrong两个方法,从字面上可以看出来,这两个方法分别是增加引用计数和减少引用计数。我们先看一下增加引用技术吧,他做的事情比较简单,直接使用android的util函数库中的android_atomic_inc来将mCount变量加1,这个函数的加1操作是原子操作,从名字上也可以看出,这是为了线程安全考虑的。然后我们再看一下减少引用技术的操作,这个也很简单,首先使用android_atomic_dec这个原子操作函数将mCount减1,然后根据这个函数的返回值判断是不是最后一个引用计数,如果是就直接delete这个对象,如果不是就跳过。这里需要说明一下,android_atomic_dec这个函数的返回值是mCount减少之前的值相当于mCount–的值,所以这里判断的条件是1而不是0。但是现在我们有一个问题这些增加和减少引用计数的方法是哪里调用的呢?还记得我们在上面那个代码中的sp类吗?对,就是它调用的!我们来看一下它的代码:
它的代码路径:/system/core/include/utils/StrongPointer.h,代码内容如下:

可以看到,它的内部方法基本很少,大部分都是运算符的重载。我们先看一下它的构造器:

首先,这个类是一个模板类,具体的对象类型是一个泛型。我们可以看到在它的构造器中将目标对象的引用赋值给m_ptr指针,然后如果目标对象的指针不为空的话直接调用它的incStrong方法将引用计数值加1。这是使用构造器传递指针的方式进行初始化的方式,我们上面的代码并没有使用这个方式,我们使用的是它的=号运算符重载:

可以看到这里才是我们上面代码使用的地方,这里和构造器逻辑基本类似,也是直接调用incStrong方法将引用加1。这里需要说明一下,这个方法考虑了sp指针重新赋值的情况,也就是说如果原本的m_ptr不为空,即原本是有指向的,现在需要先减少目标对象的引用计数,然后再将新的指针赋值给它。也就是说只要我们执行这条代码:

sp<LightClass> ptrOut = ptr;

就会执行上面的代码,然后引用计数就加1。相反如果我们把指针赋值为NULL或者别的值那么目标对象的引用计数就会减少。
这样一来,目标对象只要继承自LightRefBase类,并且我们使用sp类指针对引用就能实现对象的自动销毁,而不用再手动地执行delete了。
以上就是LightRefBase的分析,这是android的轻量级智能指针方案,实现和使用都比较简单,代码清爽不繁杂,这也就是他为什么叫轻量级的原因。

RefBase

如果说上面的LightRefBase是轻量级的,那么RefBase就应该是重量级的了,它的名字中少了light。Android为神马要引入这个类呢?想一下这样一个场景,现在有两个对象:A和B,对象A中有B的引用,因此B的引用等于1;对象B中有A的引用,因此对象A的引用对于1;现在问题来了,这两个对象和外界的任何对象都没有关系,也就说除了A和B两者之间有关系,别人和他们都没有关系!现在他们就是多余的了,应该被销毁!但是由于A和B的引用计数都是1,不为0,因此使用我们上面的方案解决不了了!还是会有内存泄露问题!怎么办呢??解决的办法是这样的,将引用分类,分为两类:强引用和弱引用。强引用就是我们上面使用的那种,弱引用是什么呢?弱引用从字面上引用的力度比强引用要弱,事实确实是这样。弱引用弱在哪里呢?弱在保证使用对象的可靠性上。这么说有点抽象,具体来说吧,像上面说的那个问题,如果A对象对B对象的引用是强引用的话,那么B对象对A对象必须是弱引用,否则还有刚才说的循环引用的问题。对象的销毁,关注的是对象的强引用,而不是对象的弱引用,也就是说如果对象的强引用为0的话不管对象的弱引用是多少直接delete掉!这就是弱引用弱的地方,也就是说你想使用的对象不一定存在呢!!另外,还有一个问题,那就是既然对象可能不存了,弱引用怎么使用这个对象呢?面对这个问题,有这样一个规定:
1. 弱引用在使用之前不如先升级为强引用才行。
如果对象不存在了,那么升级弱引用是失败的,自然就可以避免引用对象存在不确定性的问题了。说了这么多,我们现在来分析一下RefBase的代码,它的代码和LightRefBase类存在于一个文件中: /system/core/include/utils/RefBase.h

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

这个看起来有些复杂,下面我们来一步一步分析它的实现。首先他和LightRefBase一样,只是实现的功能不一样而已,都是目标类的基类,你的目标类必须是这个类的子类。接下来我们以强指针和弱指针为两条线路分析一下。

sp(强指针)

很多人刚开始看到sp的时候,都会以为sp是smart pointer的缩写,其实不是他是strong pointer的缩写。sp类的实现我们在前面分析LightRefBase类的时候已经分析过了,它的代码还是比较简单,主要就是一些运算符的重载。这里我们重点分析一下RefBase和sp的协作。前面提到,sp类是一个模板类,它的目标类型可以是任何类,也就是说可以是LightRefBase类的子类,当然也可以是RefBase类的子类。我们看到RefBase类提供的方法比较多,我们先看下RefBase类也提供了incStrong和decStrong方法,并且还有getStrongCount调试方法这个和LightRefBase是一样的。因此,在强指针这块,LightRefBase和RefBase差别不是很大。

wp(弱指针)

弱指针的实现才是重头戏,毕竟弱指针的提出就是为了解决上面提到的循环引用的问题。在进一步分析RefBase之前,我们先看一下wp也就是弱指针的实现。弱指针的实现在:/system/core/include/utils/RefBase.h文件中:

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

和强指针一样,wp也是一个模板类,因为目标类的类型是不确定的。我们看到wp类提供的方法也不是很多,很多都是一些运算符的重载。我们先看一下构造器的实现:

template<typename T>
wp<T>::wp(T* other)
    : m_ptr(other)

    if (other) m_refs = other->createWeak(this);

构造器中我们看到直接将目标对象的指针赋值给了m_ptr,然后就调用RefBase的createWeak方法:

RefBase::weakref_type* RefBase::createWeak(const void* id) const

    mRefs->incWeak(id);
    return mRefs;

这个方法直接调用weakref_type类对象的incWeak方法增加一个弱引用计数,那么weakref_type类是什么呢?我们可以看到RefBase类中提供了这个类,它是一个内部类:

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

这个类是实际表示引用计数的类,为什么这么说呢?我们看以下RefBase类的实现就知道了,RefBase的实现代码:system/core/libutils/RefBase.cpp,这个代码中有一个叫做weakref_impl的内部类:

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)  

#else

    weakref_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_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) 
        //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 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) 
        addRef(&mWeakRefs, id, mWeak);
    

    void removeWeakRef(const void* id) 
        if (!mRetain) 
            removeRef(&mWeakRefs, id);
         else 
            addRef(&mWeakRefs, id, -mWeak);
        
    

    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
;

这个类的代码有点长,其实我们仔细看一下大部分都是DEBUG_REFS等宏控制的调试代码,我们分析的时候可以直接跳过,除了这些代码剩下的基本就是这些了:

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 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)  

很精简是吧?我们看到weakref_impl类是weakref_type类的子类,并且在release版本中那些调试函数的实现全部是空的,主要就是这个类中的几个成员变量需要我们关注:

volatile int32_t    mStrong;
volatile int32_t    mWeak;
RefBase* const      mBase;
volatile int32_t    mFlags;

从名称也可以看出来,第一个是强引用计数,第二个是弱引用计数,第三个是一个指向RefBase类的指针,这个指针实际指向的是目标类的对象,因为目标类是RefBase类的子类,第四个是标志位,这个标志位主要用来管理对象的生命周期的,这个后面会说明。其实这里的weakref_impl就相当于LightRefBase里面的mCount,只是我们这里的RefBase需要管理强指针和弱指针,一个变量肯定是不行的,所以这里需要一个类来表示才行。
现在看来,wp,RefBase,weakref_impl类的关系有点乱,不太好理解,我们看一下下面的图:

其中wp是操作的指针类,这个类中包含指向RefBase实际目标子类对象的指针和一个指向weakref_impl类对象的指针;RefBase类包含了一个指向weakref_impl类对象的一个指针,用来管理引用计数;weakref_impl类就是实际的计数器,这个里面也包含了RefBase类子类的对象指针,另外,它是weakref_type类的子类。这些关系,需要读者认真理解参悟之前给出的代码才能弄明白的,一言半语只能明白个大概。
接下来的重点就是弄明白这几个类是怎么实现计数管理的目标的。之前我们说到了createWeak这个方法,这个方法直接调用了weakref_type类的incWeak方法,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 = android_atomic_inc(&impl->mWeak);
    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);

可以看到最终调用了android_atomic_inc这个原子操作函数将weakref_impl类对象的mWeak变量增加了1。到这里我们就明白了在构造器中是怎么实现弱引用计数的管理的了。现在我们再看一下=号运算符重载部分的操作:

template<typename T>
wp<T>& wp<T>::operator = (T* other)

    weakref_type* newRefs =
        other ? other->createWeak(this) : 0;
    if (m_ptr) m_refs->decWeak(this);
    m_ptr = other;
    m_refs = newRefs;
    return *this;

基本逻辑还是一样的,先看目标对象的指针是不是空,如果不是空就调用createWeak,然后如果m_ptr不为空的话,也就是先前有指向那就先decWeak,释放弱引用计数,然后在将目标对象指针和weakref_type对象指针赋值。这一点和强指针的操作是一样的。
这里我们就基本分析完了弱引用计数的管理过程,但是之前说到,弱指针想要使用目标对象的方法,就必须将弱指针升级为强指针。那么怎么升级呢?前面我们在看wp类的定义时不知道大家有没有注意到这个方法:

// promotion to sp
sp<T> promote() const;

是的,就是这个方法,从字面意思上看,这个方法就是将弱指针升级为强指针的方法。我们看一下这个方法的实现:

template<typename T>
sp<T> wp<T>::promote() const

    sp<T> result;
    if (m_ptr && m_refs->attemptIncStrong(&result)) 
        result.set_pointer(m_ptr);
    
    return result;

可以看到这里的操作就是通过weakref_type类的attemptIncStrong方法来获得强指针应用,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) 
        // we're in the easy/common case of promoting a weak-reference
        // from an existing strong reference.
        if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) 
            break;
        
        // the strong count has changed on us, we need to re-assert our
        // situation.
        curCount = impl->mStrong;
    

    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) 
        // we're now in the harder case of either:
        // - there never was a strong reference on us
        // - or, all strong references have been released以上是关于Android智能指针浅析的主要内容,如果未能解决你的问题,请参考以下文章

浅析C++智能指针和enable_shared_from_this 机制

auto_ptr浅析

C++ 浅析智能指针

浅析 C++智能指针和 enable_shared_from_this 机制

智能指针的概念和实现

Android系统的智能指针(轻量级指针强指针和弱指针)的实现原理分析