作者:刘昊昱

博客:http://blog.csdn.net/liuhaoyutz

Android版本:4.4.2

在上一篇文章中,我们分析了Android智能指针中的强指针sp,本文我们来分析弱指针wp。为什么需要弱指针wp呢?我们来考虑下面一种场景:有两个类CParent和CChild,CParent类中有一个智能指针指向CChild对象,CChild类中有一个智能指针指向CParent对象

class CParent :public LightRefBase<CParent>{       ……       sp<CChild> spc;       ……} class CChild :public LightRefBase<CChild>{       ……       sp<CParent> spp       ……}


分别创建CParent类对象parent和CChild对象child,让parent.spc指向child,让child.spp指向parent。这样,parent和child的引用计数器的值都是1,当要释放parent和child时,因为它们的引用计数器都是1,并且系统一次只能析构一个对象,这就造成一种死锁,无法析构parent和child对象中的任何一个。这样,也同样造成内存泄漏的问题。为此,Android引入了弱指针wp,定义在frameworks/rs/cpp/util/RefBase.h文件中,我们先来看wp的定义:

197template<typename T>198class wp199{200public:201    typedef typename RefBase::weakref_typeweakref_type;202203    inline wp() : m_ptr(0) { }204205    wp(T* other);206    wp(const wp<T>& other);207    wp(const sp<T>& other);208    template<typename U> wp(U* other);209    template<typename U> wp(constsp<U>& other);210    template<typename U> wp(constwp<U>& other);211212    ~wp();213214    // Assignment215216    wp& operator = (T* other);217    wp& operator = (const wp<T>&other);218    wp& operator = (const sp<T>&other);219220    template<typename U> wp& operator= (U* other);221    template<typename U> wp& operator= (const wp<U>& other);222    template<typename U> wp& operator= (const sp<U>& other);223224    void set_object_and_refs(T* other,weakref_type* refs);225226    // promotion to sp227228    sp<T> promote() const;229230    // Reset231232    void clear();233234    // Accessors235236    inline weakref_type* get_refs() const { return m_refs; }237238    inline T* unsafe_get() const { return m_ptr; }239240    // Operators241242    COMPARE_WEAK(==)243    COMPARE_WEAK(!=)244    COMPARE_WEAK(>)245    COMPARE_WEAK(<)246    COMPARE_WEAK(<=)247    COMPARE_WEAK(>=)248249    inline bool operator == (constwp<T>& o) const {250        return (m_ptr == o.m_ptr) &&(m_refs == o.m_refs);251    }252    template<typename U>253    inline bool operator == (constwp<U>& o) const {254        return m_ptr == o.m_ptr;255    }256257    inline bool operator > (constwp<T>& o) const {258        return (m_ptr == o.m_ptr) ? (m_refs> o.m_refs) : (m_ptr > o.m_ptr);259    }260    template<typename U>261    inline bool operator > (constwp<U>& o) const {262        return (m_ptr == o.m_ptr) ? (m_refs> o.m_refs) : (m_ptr > o.m_ptr);263    }264265    inline bool operator < (constwp<T>& o) const {266        return (m_ptr == o.m_ptr) ? (m_refs< o.m_refs) : (m_ptr < o.m_ptr);267    }268    template<typename U>269    inline bool operator < (constwp<U>& o) const {270        return (m_ptr == o.m_ptr) ? (m_refs< o.m_refs) : (m_ptr < o.m_ptr);271    }272                         inline bool operator!= (const wp<T>& o) const { return m_refs != o.m_refs; }273    template<typename U> inline booloperator != (const wp<U>& o) const { return !operator == (o); }274                         inline bool operator<= (const wp<T>& o) const { return !operator > (o); }275    template<typename U> inline booloperator <= (const wp<U>& o) const { return !operator > (o); }276                         inline bool operator>= (const wp<T>& o) const { return !operator < (o); }277    template<typename U> inline booloperator >= (const wp<U>& o) const { return !operator < (o); }278279private:280    template<typename Y> friend class sp;281    template<typename Y> friend class wp;282283    T*              m_ptr;284    weakref_type*   m_refs;285};


可以看到,弱指针wp与强指针sp基本内容是类似的,但是又有如下区别:

1、wp多了一个weakref_type类型的指针变量m_refs。

2、wp有一个promote函数,用于将wp升级为sp。

3、还有一点重要区别,后面我们会看到,wp目标对象的父类是RefBase而不是LightRefBase。

Android规定:

1、当一个对象强引用计数为0时,不论弱引用计数是否为0,都可以释放该对象。

2、我们不能通过弱指针wp直接操作引用对象,如果要操作,必须先将wp通过promote函数升级为sp才行。

在frameworks/rs/cpp/util/RefBase.h文件中,RefBase类定义如下:

65class RefBase 66{ 67public: 68            void            incStrong(const void* id) const; 69            void            decStrong(const void* id) const; 70 71            void            forceIncStrong(const void* id)const; 72 73            //! DEBUGGING ONLY: Get currentstrong ref count. 74            int32_t         getStrongCount() const; 75 76    class weakref_type 77    { 78    public: 79        RefBase*            refBase() const; 80 81        void                incWeak(const void* id); 82        void                decWeak(const void* id); 83 84        // acquires a strong reference if thereis already one. 85        bool                attemptIncStrong(const void*id); 86 87        // acquires a weak reference if thereis already one. 88        // This is not always safe. seeProcessState.cpp and BpBinder.cpp 89        // for proper use. 90        bool                attemptIncWeak(const void* id); 91 92        //! DEBUGGING ONLY: Get current weakref count. 93        int32_t             getWeakCount() const; 94 95        //! DEBUGGING ONLY: Print referencesheld on object. 96        void                printRefs() const; 97 98        //! DEBUGGING ONLY: Enable tracking forthis object. 99        // enable -- enable/disable tracking100        // retain -- whentracking is enable, if true, then we save a stack trace101        //           for each reference and dereference;when retain == false, we102        //           match up references and dereferencesand keep only the103        //           outstanding ones.104105        void                trackMe(bool enable, boolretain);106    };107108            weakref_type*   createWeak(const void* id) const;109110            weakref_type*   getWeakRefs() const;111112            //! DEBUGGING ONLY:Print references held on object.113    inline  void           printRefs() const {getWeakRefs()->printRefs(); }114115            //! DEBUGGING ONLY:Enable tracking of object.116    inline  void            trackMe(bool enable, bool retain)117    {118       getWeakRefs()->trackMe(enable, retain);119    }120121    typedef RefBase basetype;122123protected:124                           RefBase();125    virtual                 ~RefBase();126127    //! Flags forextendObjectLifetime()128    enum {129       OBJECT_LIFETIME_STRONG  = 0x0000,130        OBJECT_LIFETIME_WEAK    = 0x0001,131       OBJECT_LIFETIME_MASK    = 0x0001132    };133134            void            extendObjectLifetime(int32_t mode);135136    //! Flags foronIncStrongAttempted()137    enum {138        FIRST_INC_STRONG =0x0001139    };140141    virtual void            onFirstRef();142    virtual void            onLastStrongRef(const void* id);143    virtual bool            onIncStrongAttempted(uint32_tflags, const void* id);144    virtual void            onLastWeakRef(const void* id);145146private:147    friend classReferenceMover;148    static voidmoveReferences(void* d, void const* s, size_t n,149            constReferenceConverterBase& caster);150151private:152    friend class weakref_type;153    class weakref_impl;154155                           RefBase(const RefBase& o);156            RefBase&        operator=(const RefBase& o);157158        weakref_impl* constmRefs;159};


与LightRefBase给sp指向的对象提供引用计数器类似,RefBase用于给被wp指向的对象提供引用计数器功能。LightRefBase的引用计数器具体实现为一个整数LightRefBase.mCount,但是我们在RefBase类中并没有一个对应的整数作为引用计数器,那么RefBase的引用计数器是谁呢?实际上是RefBase.mRefs,它是weakref_impl类的指针。weakref_impl类中有两个成员变量mStrong和mWeak,即强引用计数和弱引用计数。RefBase.mRefs是在RefBase的构造函数中进行初始化的:

579RefBase::RefBase()580    : mRefs(newweakref_impl(this))581{582}


580行,new一个weakref_impl对象,赋值给RefBase.mRefs。

RefBase::weakref_impl定义在system/core/libutils/RefBase.cpp文件中,如下所示:

60class RefBase::weakref_impl : public RefBase::weakref_type 61{ 62public: 63    volatile int32_t    mStrong; 64    volatile int32_t    mWeak; 65    RefBase* const      mBase; 66    volatile int32_t    mFlags; 67 68#if !DEBUG_REFS 69 70    weakref_impl(RefBase* base) 71        : mStrong(INITIAL_STRONG_VALUE) 72        , mWeak(0) 73        , mBase(base) 74        , mFlags(0) 75    { 76    } 77 78    void addStrongRef(const void* /*id*/) { } 79    void removeStrongRef(const void* /*id*/) {} 80    void renameStrongRefId(const void*/*old_id*/, const void* /*new_id*/) { } 81    void addWeakRef(const void* /*id*/) { } 82    void removeWeakRef(const void* /*id*/) { } 83    void renameWeakRefId(const void*/*old_id*/, const void* /*new_id*/) { } 84    void printRefs() const { } 85    void trackMe(bool, bool) { } 86 87#else    ……    ……313#endif314};


weakref_impl类的定义内容虽然很长,但是从87行到最后都是用于debug调试,可以忽略。78-85行定义的函数都没有具体实现,所以也可以忽略。

70-76行,构造函数中对mStrong、mWeak、mBase、mFlags进行初始化。mStrong被初始化为INITIAL_STRONG_VALUE,该宏定义在system/core/libutils/RefBase.cpp文件中:

56#define INITIAL_STRONG_VALUE (1<<28)

看起来weakref_impl类只是提供了mStrong、mWeak、mBase、mFlags四个成员变量,并进行初始化,没有实现什么功能,但是要注意weakref_impl继承自RefBase::weakref_type类。

和分析sp时一样,我们考虑要让wp指向一个对象(该对象的弱引用计数应该加1),可能通过wp的构造函数,也可能通过重载的“=”赋值运算符。我们来看wp的构造函数,如下:

295template<typename T>296wp<T>::wp(T* other)297    : m_ptr(other)298{299    if (other) m_refs =other->createWeak(this);300}


再来看重载的赋值运算符,如下:

350template<typename T>351wp<T>& wp<T>::operator = (T* other)352{353    weakref_type* newRefs =354        other ?other->createWeak(this) : 0;355    if (m_ptr)m_refs->decWeak(this);356    m_ptr = other;357    m_refs = newRefs;358    return *this;359}


注意,这两个函数都没有直接增加对象other的弱引用计数(即RefBase.mRefs->mWeak),实际上,是通过调用other->createWeak(this)增加other的弱引用计数。该函数定义在system/core/libutils/RefBase.cpp文件中:

568RefBase::weakref_type* RefBase::createWeak(const void* id) const569{570    mRefs->incWeak(id);571    return mRefs;572}


570行调用mRefs即weakref_impl类的inWeak函数,给弱引用计数加1。

571行,返回RefBase.mRefs,注意它是weakref_impl类型指针。而在wp构造函数和重载的赋值运算符中,createWeak函数的返回值赋值给wp.m_refs。这样,通过wp.m_refs和other.mRefs都可以访问到引用计数器weakref_impl。

该函数定义如下:

387void RefBase::weakref_type::incWeak(const void* id)388{389    weakref_impl* const impl =static_cast<weakref_impl*>(this);390    impl->addWeakRef(id);391    const int32_t c =android_atomic_inc(&impl->mWeak);392    ALOG_ASSERT(c >= 0,"incWeak called on %p after last weak ref", this);393}


390行,addWeakRef函数是空函数,没有实现。

391行,调用android_atomic_inc,给弱引用计数mWeak加1。

分析到这里,我们就清楚怎样给弱引用计数加1的了。

再来看wp的析构函数:

344template<typename T>345wp<T>::~wp()346{347    if (m_ptr)m_refs->decWeak(this);348}


其调用的是m_refs即weakref_type.decWeak函数,该函数定义如下:

396void RefBase::weakref_type::decWeak(const void* id)397{398    weakref_impl* const impl =static_cast<weakref_impl*>(this);399    impl->removeWeakRef(id);400    const int32_t c =android_atomic_dec(&impl->mWeak);401    ALOG_ASSERT(c >= 1,"decWeak called on %p too many times", this);402    if (c != 1) return;403404    if((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {405        // This is the regularlifetime case. The object is destroyed406        // when the last strongreference goes away. Since weakref_impl407        // outlive the object,it is not destroyed in the dtor, and408        // we'll have to do ithere.409        if (impl->mStrong ==INITIAL_STRONG_VALUE) {410            // Special case: wenever had a strong reference, so we need to411            // destroy theobject now.412            deleteimpl->mBase;413        } else {414            // ALOGV("Freeingrefs %p of old RefBase %p\n", this, impl->mBase);415            delete impl;416        }417    } else {418        // less common case:lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}419       impl->mBase->onLastWeakRef(id);420        if ((impl->mFlags&OBJECT_LIFETIME_MASK)== OBJECT_LIFETIME_WEAK) {421            // this is theOBJECT_LIFETIME_WEAK case. The last weak-reference422            // is gone, we candestroy the object.423            deleteimpl->mBase;424        }425    }426}


400行,调用android_atomic_dec减小弱引用计数。

402行,如果弱引用计数不为0,则直接退出。

404-425行,根据是否是强引用,分别进行释放工作。

如果用一个sp指针指向一个继承了RefBase的类对象时,会发生什么呢?从上一篇分析sp的文章中,我们知道此时会调用RefBase.incStrong函数,该函数定义如下:

318void RefBase::incStrong(const void* id) const319{320    weakref_impl* const refs =mRefs;321    refs->incWeak(id);322323    refs->addStrongRef(id);324    const int32_t c =android_atomic_inc(&refs->mStrong);325    ALOG_ASSERT(c > 0,"incStrong() called on %p after last strong ref", refs);326#if PRINT_REFS327    ALOGD("incStrong of %pfrom %p: cnt=%d\n", this, id, c);328#endif329    if (c !=INITIAL_STRONG_VALUE)  {330        return;331    }332333   android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);334   refs->mBase->onFirstRef();335}


320行,mRefs就是该RefBase对应的计数器。

321行,增加弱引用计数。

323行,addStrongRef是一个空函数。

324行,调用android_atomic_inc增加强引用计数,即weakref_impl.mStrong。

329-331行,如果不是第一次被强指针引用,直接返回。

333行,如果是第一次被强指针引用,mStrong的值还需要减去INITIAL_STRONG_VALUE,其值才为1。

334行,refs->mBase->onFirstRef()是一个空函数。

强引用被释放时,会调用decStrong函数:

337void RefBase::decStrong(const void* id) const338{339    weakref_impl* const refs =mRefs;340   refs->removeStrongRef(id);341    const int32_t c =android_atomic_dec(&refs->mStrong);342#if PRINT_REFS343    ALOGD("decStrong of %pfrom %p: cnt=%d\n", this, id, c);344#endif345    ALOG_ASSERT(c >= 1,"decStrong() called on %p too many times", refs);346    if (c == 1) {347       refs->mBase->onLastStrongRef(id);348        if((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {349            delete this;350        }351    }352    refs->decWeak(id);353}


339行,mRefs就是该RefBase对应的计数器。

340行,removeStrongRef函数是一个空函数。

341行,将强引用计数mStrong减1。

346行,当强引用全部被释放后,释放该对象。

352行,调用decWeak函数给弱引用计数减1。

更多相关文章

  1. 箭头函数的基础使用
  2. Python技巧匿名函数、回调函数和高阶函数
  3. 浅析android通过jni控制service服务程序的简易流程
  4. Android(安卓)Resource介绍和使用
  5. Android(安卓)bluetooth介绍(四): a2dp connect流程分析
  6. Android架构分析之使用自定义硬件抽象层(HAL)模块
  7. SlidingMenu和ActionBarSherlock结合做出出色的App布局,Facebook
  8. Android(安卓)如何开发 Bottom Navigation 风格
  9. Android中OpenMax的适配层

随机推荐

  1. Android Pull Refresh View
  2. targetSdkVersion 23以下6.0中调用checkS
  3. Android下使用C语言的四种编译方式
  4. Android SDK 目录和作用的分析详解
  5. 简单android Service 创建与启动示例
  6. Android 到ARM versatile PB板移植主要步
  7. Android ApiDemos示例解析(108):Views->C
  8. Android sdk 接入时遇到的错误解决方案
  9. 转:Android listview 实现分页
  10. Android Bitmap 圆角