笔者:刘蒿羽

博客: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 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<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);
211
212 ~wp();
213
214 // Assignment
215
216 wp& operator = (T* other);
217 wp& operator = (const wp<T>&other);
218 wp& operator = (const sp<T>&other);
219
220 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);
223
224 void set_object_and_refs(T* other,weakref_type* refs);
225
226 // promotion to sp
227
228 sp<T> 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<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 }
256
257 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 }
264
265 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); }
278
279private:
280 template<typename Y> friend class sp;
281 template<typename Y> 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的构造函数,例如以下:

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) 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<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;
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\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-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\n", 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\n", 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结构分析Android智能指针(两)的更多相关文章

  1. Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6786239 Android 系统的运行时库层代 ...

  2. ZT自老罗的博客 Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析

    Android系统的智能指针(轻量级指针.强指针和弱指针)的实现原理分析 分类: Android 2011-09-23 00:59 31568人阅读 评论(42) 收藏 举报 androidclass ...

  3. android分析之智能指针

    智能指针是一个包装类,该类有一个指针指向真正的类对象 引用计数型智能指针,该引用计数是在应该被真正类所持有,而非包装类(智能指针) 为了方便,会将引用计数单独实现在一个类中,这样所有继承它的类都有计数 ...

  4. Android系统智能指针的设计思路(轻量级指针、强指针、弱指针)

    本博客为原创,转载请注明出处,谢谢. 参考博文:Android系统的智能指针(轻量级指针.强指针和弱指针)的实现原理分析 C++中最容易出错的地方莫过于指针了,指针问题主要有两类,一是内存泄露,二是无 ...

  5. Android智能指针SP WP使用方法介绍

    Android手机操作系统既然是开源的操作系统.那么在具体的文件夹中就会存放着各种相关功能的开源代码.我们在使用的时候可以根据这些源代码进行相应的修改就能轻松的完成我们所需的功能.在这里大家就一起来看 ...

  6. c++智能指针介绍_补充

    不明白我做错了什么,这几天老婆给我冷战了起来,也不给我开视频让我看娃了..哎,心累!趁着今晚的一些空闲时间来对智能指针做个补充吧. 写完上篇“智能指针介绍”后,第二天上班途中时,突然一个疑问盘踞在心头 ...

  7. 异常处理与MiniDump详解(2) 智能指针与C++异常

    write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie 讨论新闻组及文件 一.   综述 <异常处理与MiniDump详解(1) C++异常>稍 ...

  8. android 智能指针的学习先看邓凡平的书扫盲 再看前面两片博客提升

    android 智能指针的学习先看邓凡平的书扫盲 再看前面两片博客提升

  9. Android智能指针sp wp详解

    研究Android的时候,经常会遇到sp.wp的东西,网上一搜,原来是android封装了c++中对象回收机制.说明:1. 如果一个类想使用智能指针,那么必须满足下面两个条件:    a. 该类是虚基 ...

随机推荐

  1. 【翻译】要理解Ext JS 5小工具

    原版的:Understanding Widgets in Ext JS 5 在Ext JS 5,引入了新的"widgetcolumn",支持在网格的单元格中放置组件. 同一时候,还 ...

  2. 在Web.Config文件中使用configSource,避免动态修改web.config导致asp.net重启(另添加一个Config文件用于管理用户数据)

    原文:在Web.Config文件中使用configSource,避免动态修改web.config导致asp.net重启(另添加一个Config文件用于管理用户数据) 我们都知道,在asp.net中修改 ...

  3. Android使用开源项目Xutils实现多线程下载文件

    #1.下载utils项目 https://github.com/wyouflf/xUtils #2布局文件里实现UI <LinearLayout xmlns:android="http ...

  4. Java线程学习笔记(一个)

    一个.正在创建的线程: 老掉牙的话题了.继承 java.lang.Thread父类或者实现Runnalbe接口.这里就提一句: class Thread implements Runnable Thr ...

  5. POJ 1659 Frogs&#39; Neighborhood(度序列组成)

    意甲冠军  中国 依据Havel-Hakimi定理构图即可咯  先把顶点按度数从大到小排序  可图的话  度数大的顶点与它后面的度数个顶点相连肯定是满足的  出现了-1就说明不可图了 #include ...

  6. JS达到Web指定保存的和打印功能的内容

    背景 首先,说说文章的背景.近期手中的一个项目,因为需求中要求提供Web界面的打印功能.当然假设没有打印机,还能够提供保存到本地.项目组长把这个"小任务"分给了我.本着努力为组长分 ...

  7. poj2524

    说来惭愧啊..现在才会并查集.我竟然给我妈妈讲明白并查集怎么回事了- - #define _CRT_SECURE_NO_WARNINGS #include <iostream> using ...

  8. 关于 cookie 使用中遇到的问题

    前段时间在一个项目中涉及到cookie的存取,于是打算封装一个 cookie 的CRUD .按理来说,这本身是一个很简单的问题,不注意的话简单的问题也有大坑. /** * Set or get coo ...

  9. RH133读书笔记(11)-Lab 11 System Rescue and Troubleshooting

    Lab 11 System Rescue and Troubleshooting Goal: To build skills in system rescue procedures. Estimate ...

  10. BZOJ 1901 Zju 2112 Dynamic Rankings 与更改的树董事长

    标题效果:给定一个序列,单点变化,询价区间k大. 思维:假设没有变化.然后划分树就可以解决,但树的分工仍然是一棵树,它不支持的变化. 主席舒变化实际上是在外带fenwick右护套层值段树,但正确的值线 ...