博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android结构分析Android智能指针(两)
阅读量:4975 次
发布时间:2019-06-12

本文共 13016 字,大约阅读时间需要 43 分钟。

笔者:刘蒿羽 

博客:

Android版本号:4.4.2

 

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

class CParent :public LightRefBase
{ …… sp
spc; ……} class CChild :public LightRefBase
{ …… sp
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
198class wp199{200public:201 typedef typename RefBase::weakref_typeweakref_type;202203 inline wp() : m_ptr(0) { }204205 wp(T* other);206 wp(const wp
& other);207 wp(const sp
& other);208 template
wp(U* other);209 template
wp(constsp
& other);210 template
wp(constwp
& other);211212 ~wp();213214 // Assignment215216 wp& operator = (T* other);217 wp& operator = (const wp
&other);218 wp& operator = (const sp
&other);219220 template
wp& operator= (U* other);221 template
wp& operator= (const wp
& other);222 template
wp& operator= (const sp
& other);223224 void set_object_and_refs(T* other,weakref_type* refs);225226 // promotion to sp227228 sp
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
& o) const {250 return (m_ptr == o.m_ptr) &&(m_refs == o.m_refs);251 }252 template
253 inline bool operator == (constwp
& o) const {254 return m_ptr == o.m_ptr;255 }256257 inline bool operator > (constwp
& o) const {258 return (m_ptr == o.m_ptr) ? (m_refs> o.m_refs) : (m_ptr > o.m_ptr);259 }260 template
261 inline bool operator > (constwp
& 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
& o) const {266 return (m_ptr == o.m_ptr) ? (m_refs< o.m_refs) : (m_ptr < o.m_ptr);267 }268 template
269 inline bool operator < (constwp
& 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
& o) const { return m_refs != o.m_refs; }273 template
inline booloperator != (const wp
& o) const { return !operator == (o); }274 inline bool operator<= (const wp
& o) const { return !operator > (o); }275 template
inline booloperator <= (const wp
& o) const { return !operator > (o); }276 inline bool operator>= (const wp
& o) const { return !operator < (o); }277 template
inline booloperator >= (const wp
& o) const { return !operator < (o); }278279private:280 template
friend class sp;281 template
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
296wp
::wp(T* other)297 : m_ptr(other)298{299 if (other) m_refs =other->createWeak(this);300}

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

350template
351wp
& wp
::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
(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
345wp
::~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
(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。

版权声明:本文博主原创文章,博客,未经同意不得转载。

转载于:https://www.cnblogs.com/mengfanrong/p/4839557.html

你可能感兴趣的文章
Forbidden You don't have permission to access / on this server.
查看>>
Intellij Idea新建web项目(转)
查看>>
用JAVA编写浏览器内核之实现javascript的document对象与内置方法
查看>>
centos iptables
查看>>
unity3d 移动与旋转 2
查看>>
寻找二叉查找树中比指定值小的所有节点中最大的那个节点
查看>>
如何设置输入框达到只读效果
查看>>
RT3070 USB WIFI 在连接socket编程过程中问题总结
查看>>
MIS外汇平台荣获“2013年全球最佳STP外汇交易商”
查看>>
LeetCode 题解之Add Digits
查看>>
hdu1502 , Regular Words, dp,高精度加法
查看>>
SpringBoot在idea中的热部署配置
查看>>
MyEclipse连接SQL Server 2008数据库的操作方法
查看>>
JS验证图片格式和大小并预览
查看>>
laravel5.2 移植到新服务器上除了“/”路由 ,其它路由对应的页面显示报404错误(Object not found!)———新装的LAMP没有加载Rewrite模块...
查看>>
编写高质量代码--改善python程序的建议(六)
查看>>
windows xp 中的administrator帐户不在用户登录内怎么解决?
查看>>
接口和抽象类有什么区别
查看>>
Codeforces Round #206 (Div. 2)
查看>>
**p
查看>>