Android Architecture Analysis-Android smart pointer (2)

Source: Internet
Author: User

 

 

In the previous article, we analyzed the strong pointer sp in the Android smart pointer. In this article, we will analyze the weak pointer wp. Why do we need a weak pointer wp? Consider the following scenario: CParent and CChild. A smart pointer points to a CChild object in the CParent class, and a smart pointer points to a CParent object in the CChild class.

 

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


 

Create the CParent class objects parent and CChild respectively, and point parent. spc to child and child. spp to parent. In this way, the reference counter values of parent and child are both 1. When you want to release parent and child, because their reference counters are both 1, and the system can only parse one object at a time, this results in a deadlock and cannot parse any of the parent and child objects. This also causes memory leakage. Therefore, Android introduces the weak pointer wp, which is defined in the frameworks/rs/cpp/util/RefBase. h file. Let's first look at the definition of 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};                    
       
     
    
   
  
 


 

We can see that the basic content of the weak pointer wp and the strong pointer sp is similar, but there are the following differences:

1. wp has a weakref_type pointer variable m_refs.

2. wp has a promote function to upgrade wp to sp.

3. Another important difference is that the parent class of the wp target object is RefBase rather than LightRefBase.

Android rules:

1. When the strong reference count of an object is 0, the object can be released regardless of whether the weak reference count is 0.

2. We cannot use the weak pointer wp to directly operate the referenced object. If you want to operate, you must first upgrade wp to sp through the promote function.

In the frameworks/rs/cpp/util/RefBase. h file, the RefBase class is defined as follows:

 

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


 

Similar to LightRefBase, which provides reference counters for objects pointed to by sp, RefBase is used to provide reference counters for objects pointed to by wp. The Reference Counter of LightRefBase is implemented as an integer LightRefBase. mCount, but we do not have a corresponding integer in the RefBase class as the reference counter. Who is the reference counter of the RefBase? It is actually a RefBase. mRefs, which is a pointer to the weakref_impl class. The weakref_impl class has two member variables: mStrong and mWeak, that is, strong reference count and weak reference count. RefBase. mRefs is initialized in the RefBase constructor:

 

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


 

Row 3: A new weakref_impl object, which is assigned to RefBase. mRefs.

RefBase: weakref_impl is defined in the system/core/libutils/RefBase. cpp file, as follows:

 

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


 

The definition of weakref_impl class is long, but it is used for debug debugging from line 87 to the end, which can be ignored. The functions defined in line 8-85 are not implemented, so you can ignore them.

Lines 70-76. The constructor initializes mStrong, mWeak, mBase, and mFlags. MStrong is initialized to INITIAL_STRONG_VALUE. The macro is defined in the system/core/libutils/RefBase. cpp file:

56 # define INITIAL_STRONG_VALUE (1 <28)

It seems that the weakref_impl class only provides four member variables, mStrong, mWeak, mBase, and mFlags, and initialization. It does not implement any functions. However, you must note that weakref_impl inherits from RefBase: weakref_type class.

As with the analysis of sp, we consider that we should point wp to an object (the weak reference count of this object should be increased by 1), possibly through the wp constructor, it is also possible to use the overloaded "=" value assignment operator. Let's look at the wp constructor as follows:

 

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


 

Let's take a look at the overloaded value assignment operator, as shown below:

 

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}   


 

Note that neither of these functions directly increase the weak reference count (RefBase) of the object other. mRefs-> mWeak), in fact, is to increase the weak reference count of other by calling other-> createWeak (this. This function is defined in the system/core/libutils/RefBase. cpp file:

 

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


 

The second line calls the inWeak function of the weakref_impl class in mRefs, and Adds 1 to the weak reference count.

Row 3 returns RefBase. mRefs. Note that it is a weakref_impl pointer. In the wp constructor and the overloaded value assignment operator, the return value of the createWeak function is assigned to wp. m_refs. In this way, both wp. m_refs AND other. mRefs can access the reference counter weakref_impl.

The function is defined as follows:

 

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} 


 

Row 3: The addWeakRef function is an empty function and is not implemented.

Row 3 calls android_atomic_inc to add 1 to the weak reference count mWeak.

From this analysis, we can see how to add 1 to the weak reference count.

 

Let's take a look at wp's destructor:

 

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


 

It calls the m_refs (weakref_type.decWeak function), which is defined as follows:

 

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, 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} 


 

In row 3, android_atomic_dec is called to reduce the weak reference count.

Row 3. If the weak reference count is not 0, exit directly.

Lines 404-425 are released based on whether it is strongly referenced.

 

What happens if I use an sp pointer to point to a class object that inherits RefBase? From the previous article on sp analysis, we know that the RefBase. incStrong function will be called at this time. The function is defined as follows:

 

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, 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}


 

In row 3, mRefs is the counter corresponding to the RefBase.

321 rows to increase the weak reference count.

Row 3, addStrongRef is an empty function.

In row 324, android_atomic_inc is called to increase the strong reference count, that is, weakref_impl.mStrong.

Rows 329-331 are directly returned if it is not referenced by a strong pointer for the first time.

Row 3: If the row is referenced by a strong pointer for the first time, the mStrong value must be subtracted from INITIAL_STRONG_VALUE before the value is 1.

Row 3, refs-> mBase-> onFirstRef () is an empty function.

When a strong reference is released, the decStrong function is called:

 

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, 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}


 

In row 3, mRefs is the counter corresponding to the RefBase.

Row 3: removeStrongRef is an empty function.

In row 341, the strong reference count mStrong is reduced by 1.

Row 3: This object is released when all strong references are released.

In row 352, call the decWeak function to reduce the weak reference count by 1.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.