編輯:關於Android編程
在上一篇文章中,我們分析了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 wp 199{ 200public: 201 typedef typename RefBase::weakref_typeweakref_type; 202 203 inline wp() : m_ptr(0) { } 204 205 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); 211 212 ~wp(); 213 214 // Assignment 215 216 wp& operator = (T* other); 217 wp& operator = (const wp &other); 218 wp& operator = (const sp &other); 219 220 template wp& operator= (U* other); 221 template wp& operator= (const wp& other); 222 template wp& operator= (const sp& other); 223 224 void set_object_and_refs(T* other,weakref_type* refs); 225 226 // promotion to sp 227 228 sp promote() const; 229 230 // Reset 231 232 void clear(); 233 234 // Accessors 235 236 inline weakref_type* get_refs() const { return m_refs; } 237 238 inline T* unsafe_get() const { return m_ptr; } 239 240 // Operators 241 242 COMPARE_WEAK(==) 243 COMPARE_WEAK(!=) 244 COMPARE_WEAK(>) 245 COMPARE_WEAK(<) 246 COMPARE_WEAK(<=) 247 COMPARE_WEAK(>=) 248 249 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 } 256 257 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 } 264 265 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); } 278 279private: 280 template friend class sp; 281 template friend class wp; 282 283 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 tracking
100 // retain -- whentracking is enable, if true, then we save a stack trace
101 // for each reference and dereference;when retain == false, we
102 // match up references and dereferencesand keep only the
103 // outstanding ones.
104
105 void trackMe(bool enable, boolretain);
106 };
107
108 weakref_type* createWeak(const void* id) const;
109
110 weakref_type* getWeakRefs() const;
111
112 //! DEBUGGING ONLY:Print references held on object.
113 inline void printRefs() const {getWeakRefs()->printRefs(); }
114
115 //! DEBUGGING ONLY:Enable tracking of object.
116 inline void trackMe(bool enable, bool retain)
117 {
118 getWeakRefs()->trackMe(enable, retain);
119 }
120
121 typedef RefBase basetype;
122
123protected:
124 RefBase();
125 virtual ~RefBase();
126
127 //! Flags forextendObjectLifetime()
128 enum {
129 OBJECT_LIFETIME_STRONG = 0x0000,
130 OBJECT_LIFETIME_WEAK = 0x0001,
131 OBJECT_LIFETIME_MASK = 0x0001
132 };
133
134 void extendObjectLifetime(int32_t mode);
135
136 //! Flags foronIncStrongAttempted()
137 enum {
138 FIRST_INC_STRONG =0x0001
139 };
140
141 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);
145
146private:
147 friend classReferenceMover;
148 static voidmoveReferences(void* d, void const* s, size_t n,
149 constReferenceConverterBase& caster);
150
151private:
152 friend class weakref_type;
153 class weakref_impl;
154
155 RefBase(const RefBase& o);
156 RefBase& operator=(const RefBase& o);
157
158 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#endif
314};
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) const
569{
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;
403
404 if((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
405 // This is the regularlifetime case. The object is destroyed
406 // when the last strongreference goes away. Since weakref_impl
407 // outlive the object,it is not destroyed in the dtor, and
408 // we'll have to do ithere.
409 if (impl->mStrong ==INITIAL_STRONG_VALUE) {
410 // Special case: wenever had a strong reference, so we need to
411 // 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-reference
422 // 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) const
319{
320 weakref_impl* const refs =mRefs;
321 refs->incWeak(id);
322
323 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_REFS
327 ALOGD(incStrong of %pfrom %p: cnt=%d
, this, id, c);
328#endif
329 if (c !=INITIAL_STRONG_VALUE) {
330 return;
331 }
332
333 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) const
338{
339 weakref_impl* const refs =mRefs;
340 refs->removeStrongRef(id);
341 const int32_t c =android_atomic_dec(&refs->mStrong);
342#if PRINT_REFS
343 ALOGD(decStrong of %pfrom %p: cnt=%d
, this, id, c);
344#endif
345 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。
Android實習札記(10)---ImageView的src屬性 VS blackground屬性
問題分析 相信大家對於ImageView圖片組件並不陌生吧,見名知意,就是用來顯示圖片的咯! 而顯示圖片的話可以通過src屬性,又或者blac
android產品研發(十三)--)App輪訓操作
上一篇文章中我們講解了android app實現長連接的幾種方式,各自的優缺點以及具體的實現,一般而言使用第三方的推送服務已經可以滿足了基本的業務需求,當然了若是對技術有
從零開始學android(Tablelayout表格布局.十五.)
TableLayout就是將手機的屏幕分為一行行的形式進行數據的顯示,並且一行可以多個控件 並且可以設置控件的對齊方式,和是否為可收縮行 下面通過一行圖和一個簡單的例子來
Android——IPC機制(一)IPC概念以及Binder機制
由於IPC機制牽扯的東西比較多,所以這裡將分為一個系列進行總結主要介紹內如如下:IPC簡介 Android中的多進程模式開啟多進程模式 多進程模式的運行機制 IPC基礎概