




已阅读5页,还剩6页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
研究Android的时候,经常会遇到sp、wp的东西,网上一搜,原来是android封装了c+中对象回收机制。说明:1. 如果一个类想使用智能指针,那么必须满足下面两个条件: a. 该类是虚基类RefBase的子类或间接子类 b. 该类必须定义虚构造函数。如virtual MyClass();2. 本文以类BBinder来进行说明,其余类使用sp或wp的情况类似3. 代码路径:frameworks/base/libs/utils/RefBase.cpp frameworks/base/include/utils/RefBase.h一、calss BBinder类说明 class RefBase class IBinderclass BpBinder class BBinderclass BBinder : public IBtected: virtual BBinder();.class IBinder : public virtual RefBtected: inline virtual IBinder() .由上,可以看出BBinder和IBinder都是以public的方式继承于虚基类RefBase的。二、sp wp对象的建立过程解析:sp BB_ptr(new BBinder);这是一条定义sp指针BB_ptr的语句,他只想的对象是一个BBinder对象。如图所示。1首先看一下new BBinder时都做了什么,特别是和该机制相关的初始化。 c+中创建一个对象时,需要调用去构造函数,对于继承类,则是先调用其父类的构造函数,然后才会调用本身的 构造函数。这里new一个BBinder对象时,顺序调用了:RefBase:RefBase() : mRefs(new weakref_impl(this) inline IBinder() BBinder:BBinder() : mExtras(NULL) 主要关注的是RefBase的构造函数, 可以看出他是通过new weakref_impl(this)的结果来初始化私有成员mRefs 这里的this指向BBinder对象自身,class weakref_impl继承于类RefBase的内嵌类weakref_type,然后该类 weakref_impl又被类RefBase引用。类weakref_impl的构造函数如下: weakref_impl(RefBase* base) : mStrong(INITIAL_STRONG_VALUE)/ 1 28 , mWeak(0) , mBase(base)/ new BBinder指针 , mFlags(0) , mStrongRefs(NULL)/ sp引用链表指针 , mWeakRefs(NULL)/ wp引用链表指针 , mTrackEnabled(!DEBUG_REFS_ENABLED_BY_DEFAULT) / 1 , mRetain(false) 2new BBinder返回的是BBinder对象的指针,如:sp BB_ptr(0x?); sp实际上是一个类模板,这条语句最终是要建立一个sp的实例化对象,叫模板类BB_ptr 这里生成BB_ptr对象所调用的构造函数是: templatesp:sp(T* other) : m_ptr(other) if (other) other-incStrong(this);BB_ptr对象的私有指针指向刚刚前面生成的BBinder对象。接着调用函数incStrong(),该函数是RefBase类的成员函数,在子类中没有被重载,所以这里other-incStrong(this)的调用实际上是调用基类成员函数incStrong(this),这个this值是指向sp对象BB_ptr的指针。现在转去查看该成员函数的实现。void RefBase:incStrong(const void* id) const weakref_impl* const refs = mRefs; /* 取得BBinder对象基类中的私有只读指针mRefs */ refs-addWeakRef(id); /* 调用weakref_impl类定义时实现的成员函数addWeakRef, 见下注释1*/ refs-incWeak(id); /* 调用weakref_impl类的基类weakref_type成员函数incWeak, 见下注释2*/ refs-addStrongRef(id); / 调用weakref_impl类定义时实现的成员函数addStrongRef, 见下注释1 const int32_t c = Android_atomic_inc(&refs-mStrong); /* 该函数实际将refs-mStrong值加1,也就是增加强引用计数值。但是返回值为refs-mStrong-1 */ LOG_ASSERT(c 0, incStrong() called on %p after last strong ref, refs);#if PRINT_REFS LOGD(incStrong of %p from %p: cnt=%dn, this, id, c);#endif if (c != INITIAL_STRONG_VALUE) return; /* c = INITIAL_STRONG_VALUE, 第一个强引用产生的时候才会出现这个情况 */ Android_atomic_add(-INITIAL_STRONG_VALUE, &refs-mStrong);/* 返回值为INITIAL_STRONG_VALUE,refs-mStrong值变成1 */ const_cast(this)-onFirstRef();/*注释1*/void addWeakRef(const void* id) addRef(&mWeakRefs, id, mWeak);void addStrongRef(const void* id) addRef(&mStrongRefs, id, mStrong);addRef()是类weakref_impl的私有成员函数,addWeakRef()函数引用的是public成员变量,而addRef()函数可以操作私有数据。 struct ref_entry ref_entry* next; const void* id; int32_t ref; ; void addRef(ref_entry* refs, const void* id, int32_t mRef) if (mTrackEnabled) AutoMutex _l(mMutex); ref_entry* ref = new ref_entry; ref-ref = mRef; ref-id = id; ref-next = *refs; *refs = ref;/*新出现的ref_entry结构体加入到链表头上,如果有n个sp指针指向同一个目标对象那么这里就有n个ref_entry结构体加入到这个单链表中,该结构体记录着如下数据1. id域记录着对应的sp强指针类对象的this值2. ref域记录的是当前sp强指针类对象是第几个引用目标对象的指针3. next域指向下一个指向目标对象的sp强指针对应的ref_entry结构体类RefBase的嵌套类weakref_type的子类的私有数据mRefs的私有二级指针成员mWeakRefs指向的是最后一个sp强指针对应的ref_entry结构体指针。总结一下:一个目标对象,可能被n个sp强指针指向,那么就存在n个class sp对象,同时每一个sp对象在目标对象的虚基类对象的成员类mRefs的私有二级指针成员mWeakRefs登记了一个ref_entry结构体,这些ref_entry结构体的地址都是由该链表管理,每一个ref_entry结构体和哪一个sp对象对应,也由该链表管理。同时链接数就是该链表节点的个数*/ /*注释1*/*注释2*/void RefBase:weakref_type:incWeak(const void* id) weakref_impl* const impl = static_cast(this); / 强制类型转换,将基类指针转换成子类指针 impl-addWeakRef(id); / 调用类weakref_impl成员函数addWeakRef(),产生一个ref_entry结构体挂载mWeakRefs链表上 const int32_t c = Android_atomic_inc(&impl-mWeak);/* impl-mWeak加1,表示已存在一个weak引用。但返回值c为操作前的结果 */ LOG_ASSERT(c = 0, incWeak called on %p after last weak ref, this);/*注释2*/3上面是定义一个sp指针,下面看看定义一个wp指针式如何实现的。 wp BB_wp_ptr(BB_ptr); 下面是wp类对应上面定义类型的构造函数templatewp:wp(const sp& other) : m_ptr(other.m_ptr) if (m_ptr) m_refs = m_ptr-createWeak(this); this指针是指向wp对象的。createWeak()函数是RefBase类的成员函数。RefBase:weakref_type* RefBase:createWeak(const void* id) const mRefs-incWeak(id); return mRefs;mRefs指向的是第二步骤中产生的weakref_impl对象,调用基类weakref_type的成员函数incWeak()void RefBase:weakref_type:incWeak(const void* id) weakref_impl* const impl = static_cast(this); impl-addWeakRef(id); const int32_t c = Android_atomic_inc(&impl-mWeak);/* impl-mWeak有加1,但返回值为操作前的结果 */ LOG_ASSERT(c = 0, incWeak called on %p after last weak ref, this);三、sp、wp释放过程 sp BB_SP_ptr(BB_ptr);实际上BB_SP_ptr和前面的BB_ptr一样,指向的是同一个BBinder对象。另外需要注意的时,调用sp构造函数:templatesp:sp(const sp& other) : m_ptr(other.m_ptr) if (m_ptr) m_ptr-incStrong(this);同样是需要调用BBinder对象的incStrong()函数,使用weakref_impl对象来管理新添加进来的强引用,同时增加一个ref_entry结构体到weakref_impl对象的mStrongRefs,增加2个ref_entry结构体到weakref_impl对象的mWeakRefs。如上图所示。现在来看看释放sp、wp指针的情况。delete BB_SP_ptr;将会调用如下形式的sp析构函数:templatesp:sp() if (m_ptr) m_ptr-decStrong(this);m_ptr指向的是前面生成的BBinder对象,调用其基类函数decStrong(this),this值是指向BB_SP_ptr对象。void RefBase:decStrong(const void* id) const weakref_impl* const refs = mRefs; refs-removeStrongRef(id); / 注释3,移除mStrongRefs链表中和该sp对应的ref_entry结构体 const int32_t c = Android_atomic_dec(&refs-mStrong);/* 强引用计数减1, 但返回的是操作之前的引用计数值 */ LOG_ASSERT(c = 1, decStrong() called on %p too many times, refs); if (c = 1) /* c = 1说明刚刚removeStrongRef之前,整个系统中只存在一个sp对象引用目标对象,现在的情况就是 系统中没有任何强指针对象来引用目标对象了,此时目标对象就会被删除释放 */ const_cast(this)-onLastStrongRef(id); if (refs-mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) delete this; / mFlags =0 ,条件成立,删除目标对象,这里就会删除前面new出来的BBinder对象 / 如果此时还有其他指向该目标对象的sp指针存在的话,就不会删除目标对象 refs-removeWeakRef(id); refs-decWeak(id); /* 删除新建目标对象sp指针时在mWeakRefs链表上增加的两个ref_entry结构体 */*注释3*/void removeStrongRef(const void* id) if (!mRetain)/ mRetain 初始化成 flase removeRef(&mStrongRefs, id); /* 删除mStrongRefs链表中对应id的ref_entry一项 */* 也就是取消了该sp对象和目标对象的联系 */ else addRef(&mStrongRefs, id, -mStrong); void removeRef(ref_entry* refs, const void* id) if (mTrackEnabled) AutoMutex _l(mMutex); ref_entry* ref = *refs; while (ref != NULL) if (ref-id = id) *refs = ref-next; delete ref; return; refs = &ref-next; ref = *refs; /*注释3*/delete BB_wp_ptr;这是删除目标对象的一个wp指针,会调用wp的析构函数:templatewp:wp() if (m_ptr) m_refs-decWeak(this);调用weakref_type类的decWeak()函数,如下:void RefBase:weakref_type:decWeak(const void* id) weakref_impl* const impl = static_cast(this); impl-removeWeakRef(id);/ 移除weakref_impl对象mWeakRefs链表中对应id的ref_entry结构体 const int32_t c = Android_atomic_dec(&impl-mWeak);/ 引用计数减1 LOG_ASSERT(c = 1, decWeak called on %p too many times, this); if (c != 1) return; / c = 1, 说明这是系统中存在的指向目标对象的最后一个wp指针 if (impl-mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) if (impl-mStrong = INITIAL_STRONG_VALUE) delete impl-mBase; / delete impl; 是不是应该加上这么一句,防止用户新建了wp后,不用,马上又删除的情况呢?/* 当目标对象的最后一个wp被析构时,如果目标对象还没有建立任何一个sp,那么目标对象被删除 */ else delete impl;/* 当目标对象的最后一个wp被析构时,但此时和目标对象相关的sp全部被析构,那么impl-mStrong = 0 在最后一个sp被析构的时候,目标对象也被释放,所以此时只需要释放weakref_impl对象即可*/ else impl-mBase-onLastWeakRef(id); if (impl-mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) delete impl-mBase; 四、wp升级为sp的过程wp的定义包含了:sp promote() const;templatesp wp:promote() const return sp(m_ptr, m_refs);wp,sp互为友元类,这里promote就是以友元身份调用了sp类的构造函数: sp(T* p, weakref_type* refs);templatesp:sp(T* p, weakref_type* refs) : m_ptr(p & refs-attemptIncStrong(this) ? p : 0)这里如果升级成功,那么将会产生一个sp对象指向目标对象,原来的wp仍然存在。如果升级不成功,返回NULL看看关键函数refs-attemptIncStrong(this)bool RefBase:weakref_type:attemptIncStrong(const void* id) incWeak(id); weakref_impl* const impl = static_cast(this); int32_t curCount = impl-mStrong; LOG_ASSERT(curCount = 0, attemptIncStrong called on %p after underflow, this); while (curCount 0 & curCount != INITIAL_STRONG_VALUE) if (Android_atomic_cmpxchg(curCount, curCount+1, &impl-mStrong) = 0) break; curCount = impl-mStrong; / 系统中还有其他sp指向目标对象的情况 if (curCount mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK | impl-mBase-onIncStrongAttempted(FIRST_INC_STRONG, id); else /*发现系统中原来指向目标对象的sp全部被释放,最后一次sp释放也将目标对象释放了*/ allow = (impl-mFlags&OBJECT_LIFETIME_WEAK) = OBJECT_LIFETIME_WEAK & impl-mBase-onIncStrongAttempted(FIRST_INC_STRONG, id); if (!allow) decWeak(id); / 目标对象已经不存在了,释放前面incWeak(id)产生的ref_entry结构体 return false; curCount = Android_atomi
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论