笔者:刘蒿羽
博客:
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的定义:
197template198class 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的构造函数,例如以下:
295template296wp ::wp(T* other)297 : m_ptr(other)298{299 if (other) m_refs =other->createWeak(this);300}
再来看重载的赋值运算符,例如以下:
350template351wp & 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的析构函数:
344template345wp ::~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。
版权声明:本文博主原创文章,博客,未经同意不得转载。