`
ai_longyu
  • 浏览: 479325 次
社区版块
存档分类
最新评论

Android智能指针sp wp详解

 
阅读更多

原文:http://blog.csdn.net/lizhiguo0532/article/details/6260114

研究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 IBinder
class BpBinder class BBinder
class BBinder : public IBinder
{
...
protected:
virtual ~BBinder();
...
}
class IBinder : public virtual RefBase
{
...
protected:
inline virtual ~IBinder() { }
...
}
由上,可以看出BBinder和IBinder都是以public的方式继承于虚基类RefBase的。

二、sp wp对象的建立过程
解析:sp<BBinder> 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) {}

2》new BBinder返回的是BBinder对象的指针,如:sp<BBinder> BB_ptr(0x????????);
sp实际上是一个类模板,这条语句最终是要建立一个sp的实例化对象,叫模板类BB_ptr
这里生成BB_ptr对象所调用的构造函数是:
template<typename T>
sp<T>::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=%d\n", 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<RefBase*>(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<weakref_impl*>(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<BBinder> BB_wp_ptr(BB_ptr);
下面是wp类对应上面定义类型的构造函数
template<typename T>
wp<T>::wp(const sp<T>& 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<weakref_impl*>(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<BBinder> BB_SP_ptr(BB_ptr);
实际上BB_SP_ptr和前面的BB_ptr一样,指向的是同一个BBinder对象。另外需要注意的时,调用sp构造函数:
template<typename T>
sp<T>::sp(const sp<T>& 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析构函数:
template<typename T>
sp<T>::~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<RefBase*>(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的析构函数:
template<typename T>
wp<T>::~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<weakref_impl*>(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<T> promote() const;
template<typename T>
sp<T> wp<T>::promote() const
{
return sp<T>(m_ptr, m_refs);
}
wp,sp互为友元类,这里promote就是以友元身份调用了sp<Binder>类的构造函数: sp(T* p, weakref_type* refs);
template<typename T>
sp<T>::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<weakref_impl*>(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 <= 0 || curCount == INITIAL_STRONG_VALUE) {
bool allow;
if (curCount == INITIAL_STRONG_VALUE) {
// 发现该目标对象还没有一个sp对象与之相关联的话,那么将会新建一个对目标对象的强引用
allow = (impl->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_atomic_inc(&impl->mStrong);

if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
impl->mBase->onLastStrongRef(id);
}
}
// 走完生成一个sp的必要过程,和前面介绍的是一样
impl->addWeakRef(id);
impl->addStrongRef(id);

if (curCount == INITIAL_STRONG_VALUE) {
Android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
impl->mBase->onFirstRef();
}

return true;// 返回true
}

五、总结:
1. weakref_impl对象会随着目标对象的生成而产生,但不一定会随着目标对象的释放而释放。例如:如果目标对象被
1个sp引用,但是同时被2个wp引用,那么在sp被删除的时候,删除了目标对象,但没有删除weakref_impl对象,
只有在最后一个wp释放时,weakref_impl对象会被释放。
2. 一个目标对象被多个sp指针引用,没有wp引用的情况下。释放这些sp的时候,delete会调用sp析构函数,
然后调用RefBase类的成员函数decStrong(), 最后一个sp被释放时,weakref_impl对象数据成员mStrong会
从1减到0(注意mStrong的初始化值为1<<28, 从这个值可以判断出该目标对象有没有被sp指针引用过),
同时释放目标对象。
3. 一个目标对象被多个wp指针引用,没有sp引用的情况下。delete这些wp的时候,会调用wp的析构函数,该函数会
调用函数decWeak()。当删除最后一个wp的时候,代码中只是删除了目标对象,而没有释放weakref_impl对象,
暂时没发现在哪里释放了它。
4. 一个目标对象既有sp,又有wp来引用。如果sp先被删除光,那么最后一个sp删除的时候会释放掉目标对象,那么此时
mStrong = 0。在后续最后一个wp的释放过程中,在decWeak()函数中就会判断出impl->mStrong !=
INITIAL_STRONG_VALUE,而释放掉剩下的weakref_impl对象了。如果先所以的wp删除光,此时mWeak还等于剩余的sp
的个数,所以此时的释放情况,同第2小点的说明。
5. 从wp定义来看,wp是不能直接操作对象的,必须先升级为sp才行。这个升级的过程是依靠函数promote()来完成的。
升级成功,返回新生成的sp对象指针,升级失败,返回NULL。需要注意的是,如果目标对象之前有过sp指向,但后来
将所有的sp释放完之后,此时目标对象是不存在的,那么此时用户还想将指向该目标对象的wp升级为sp的话,
此时就返回NULL。那么这个时候我们应该delete这些剩下的wp。


分享到:
评论

相关推荐

    anroid智能指针(wp,sp)学习总结

    智能指针sp和wp在android c++源码中使用非常频繁,例如IBinder机制,但是它比c++中普通的智能指针要复杂很多,相信不少android学习者如果c++基础不是很扎实的,看起来会比较吃力和枯燥。本人在android 4.2.2源码基础...

    android智能指针详解[收集].pdf

    android智能指针详解[收集].pdf

    Android智能指针使用方法介绍

    Android智能指针使用方法介绍 Android智能指针使用方法介绍

    理解 Android sp wp 指针

    在 Windows 上调试 Android 的 Strong & Weak 指针以更好的理解 Strong & Weak 指针。

    Android系统智能指针

    在计算机系统中,资源是数量有限且对系统正常运行具有一定作用的元素。...不过系统为我们提供了智能指针,避免出现上述问题,本文将系统地分析Android系统智能指针(轻量级指针、强指针和弱指针)的实现原理。

    android中的智能指针案例

    Android中智能指针详解案例代码Android中智能指针详解案例代码Android中智能指针详解案例代码

    Android_WP_SP浅析

    【本人原创】在win32 下debug模拟;分析了sp/wp的运行机理及使用方法

    c++指针详解指针详解

    指针详解指针详解指针详解指针详解指针详解指针详解指针详解指针详解指针详解指针详解指针详解指针详解指针详解指针详解指针详解指针详解指针详解

    C++_智能指针详解

    C++ 智能指针详解 std::auto_ptr

    安卓智能指针测试 spwp.tar

    包含RefBase.h,RefBase.cpp,WeakPointer.h,StrongPointer.h,LightRefBase,模拟安卓原子操作的android_atomic.cpp,android_atomic.h,所有文件组成了安卓智能指针sp,wp,LightRefBase

    智能指针与引用计数详解

    该demo主要展现智能指针和引用计数的实现过程,总共两个类,一个智能指针类,一个引用计数类,另外附一份执行步骤资料

    c_c++指针详解 指针详解

    c_c++指针详解 c_c++指针详解 希望对大家理解指针有帮助

    c++智能指针最全知识点即面试题目总结

    本篇文章收集了近一年来所有关于智能指针的面试相关内容。以智能指针的面试题线索,穿插讲解完最常用的四种智能指针的各个方面。本文讲解4个智能指针的基本概念和特性,以及其他设计到的知识点。讲解的过程中,如果...

    智能指针与弱引用详解

    在android 中可以广泛看到的template&lt;typename&gt; class Sp 句柄类实际上是android 为实现垃圾回收机制的智能指针。智能指针是c++ 中的一个概念,因为c++ 本身不具备垃圾回收机制,而且指针也不具备构造函数和析构函数...

    C++智能指针-unique-ptr智能指针详解.pdf

    C++智能指针 智能指针_unique_ptr智能指针详解 智能指针详解 作为智能指针的⼀种,unique_ptr 指针⾃然也具备"在适当时机⾃动释放堆内存空间"的能⼒。和 shared_ptr 指针最⼤的不同之处在 于,unique_ptr 指针指向的...

    C++智能指针详解.pdf

    C++智能指针详解 智能指针详解 智能指针内容很多,重点是基本⽤法。 #include &lt;boost/shared_ptr.hpp&gt; class CBase: public boost::enable_shared_from_this&lt;CBase&gt; { public: virtual void f(){}//必须有个虚函数...

    C++智能指针测试代码

    C++ 7种智能指针测试代码

    C++智能指针详解abc

    C++智能指针详解abc

    C++智能指针用法详解

     用智能指针便可以有效缓解这类问题,本文主要讲解参见的智能指针的用法。包括:std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、boost::shared_array、boost::weak_ptr、boost:: ...

    c++智能指针的实现

    智能指针是用来实现指针指向的对象的共享的。其实现的基本思想: 每次创建类的新对象时,初始化指针并将引用计数置为1; 当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数; 对一个...

Global site tag (gtag.js) - Google Analytics