阅读android源码,Refbase,wp,sp一点所得

来源:互联网 发布:单机斗牛牛无网络破解 编辑:程序博客网 时间:2024/06/06 05:07

一、

RefBase是引用计数的类,它封装了引用计数的技术细节。包括增加强引用计数,增加弱引用计数,减少强引用计数,减少弱引用计数等等。

 但是对RefBase的具体操作,却是委托给了weakref_impl这个类。就好比RefBase是一块农田,对农田的操作由weakref_impl这个农夫来操作。

  weakref_impl是RefBase内部定义的一个类weakref_type的派生类。强和弱引用计数的实际数据也是放在weakref_impl中的.下面是 weakref_impl这个类的定义


class RefBase::weakref_impl 表示它是RefBase的内部类
public RefBase::weakref_type 表示它继承RefBase的内部类weakref_type

  class RefBase::weakref_impl : public RefBase::weakref_type{public:    std::atomic<int32_t>    mStrong;   //强引用计数    std::atomic<int32_t>    mWeak; //弱引用计数    RefBase* const          mBase;//实际对象的影子    std::atomic<int32_t>    mFlags;.........};
注意RefBase* const          mBase这个成员. 任意一个类,当他需要使用引用计数时,都需要继承RefBase这个类。在weakref_impl中设置这么一个RefBase类型的成员是什么用意?我们先看一下RefBase的构造函数,因为实际对象在构造时父类构造必须被率先调用,c++的多态!

RefBase::RefBase():mRefs(new weakref_impl(this)){//代码略}
请看初始化代码mRefs(new weakref_impl(this))也就是说父类在构造的时候,先new了一个new weakref_impl,去初始化mRefs成员,这说明,RefBase这块农田内置了一个农夫weakref_impl,且这个农田的农夫在构造时诞生了!
并且用的是this作为参数,这个this可是实际对象哦,子类构造导致基类构造执行,传递的this自然是子类,也就是实际对象!既然实际对象作为农夫的构造参数,那么我们去看看这个weakref_impl的构造参数,他是怎么处理this的。
weakref_impl(RefBase* base)        : mStrong(INITIAL_STRONG_VALUE)        , mWeak(0)        , mBase(base)        , mFlags(0)    {    }
weakref_impl的mBase成员保存的就是传递的this啊,前面说过这个this就是实际对象哦。所以,可以说weakref_impl保存了一个实际对象的引用.

现在可以看sp。sp使用了模板技术,先看一下sp的构造函数

template<typename T>  sp<T>::sp(T* other):m_ptr(other)  {if(other)other->incStrong(this);  }
T就代表着实际对象,已知实际对象是继承了RefBase的。m_ptr是sp的成员,类型就是T*,由此可见,强引用类sp内部保存了一个实际对象的引用,由成员m_ptr保存。且sp构造时调用了other->incStrong(this);
  实际上就是RefBase的方法incStrong(),不就是多态吗!other是实际对象,它继承RefBase自然就调用RefBase的incStrong()!
  
  但是强和弱引用计数的实际数据是放在weakref_impl中的,那么RefBase的方法incStrong()一旦被调用,又是如何影响到强和弱引用计数的数值变化呢?我们看看这个incStrong()函数的具体实现
void RefBase::incStrong(const void *id)  {weakref_impl *const refs = mRefs;refs->addWeakRef(id);  //空函数refs->incWeak(id);refs->addStrongRef(id);.........  }
原来在IncStrong()中生成了一个weakref_impl的指针,而这个指针等价于RefBase的成员mRefs. 前面说过了,mRefs就是指向着weakref_impl的。从而通过这个指针调用weakref_impl内部的方法实现了实际数值的改变。由此可见确实是weakref_impl在实际操作引用计数的数值。

RefBase::RefBase():mRefs(new weakref_impl(this)){//再看一眼RefBase的构造把,再次确定一下mRefs就是指向weakref_impl}


现在脉络有点清晰了。sp在构造的时候,首先将实际对象给保存起来了。

而实际对象因为它继承自RefBase, RefBase内部又保存着weakref_impl这个农夫的对象指针(农夫负责操作RefBase这块农田,农夫内部保存着实际的引用计数数值和实际对象). 所有虽然sp只保存了一个实际对象,但是只要sp愿意,它也可以定位到农夫,不是吗?

小知识点:weakref_impl在修改引用计数数值的时候,都是使用了原子级操作,android_atomic_inc() 或者 android_atomic_dec(),这2个原子级操作的函数,返回值都是旧值,这一点要注意。比如android_atomic_inc()操作前旧值是1,则函数成功新值是2,但是返回值是旧值1.

根据incStrong()代码中的实际代码,其实不光令强引用计数+1也令弱引用计数+1。其他的暂时不关注了,只记住一点,sp的构造函数令强引用计数+1,弱引用计数同时+1;

顺便再来看一下wp的构造,wp是弱引用计数,构造好几个,随便挑一个来看看

templete<typename T>wp<T>::wp(const sp<T>& other):m_ptr(other.m_ptr){if(m_ptr)m_refs = m_ptr->createWeak(this);}
m_ptr是T* 类型,同上面介绍sp时细述的一样,那这个createWeak()不出意外就是RefBase的方法咯,过去看看这个createWeak的实现

RefBase::weakref_type* RefBase::createWeak(const void*id) const{mRef->incWeak(id);return mRef;}
哈,基类RefBase的mRef就是weakref_impl*类型嘛,mRef->incWeak()不就是调用weakref_impl的方法吗?绕一圈还是调用weakref_impl的incWeak()去给弱引用计数+1,并且返回weakref_impl* 给wp的m_Refs成员。

现在对sp和wp能看出一点区别了:
sp 有T* m_ptr 成员,这个成员就是实际对象的引用,但是这个m_ptr继承自RefBase,等价于m_ptr也包含了weakref_impl*;

wp 有weakref_impl m_Refs成员,也有T* m_ptr,已知m_ptr是保存了实际对象的引用的,m_Refs代表着weakref_impl;


sp会令强引用计数+1,弱引用计数+1

wp会令弱引用计数+1



构造看完了,来看看wp的析构函数
wp<T>::~wp(){if(m_ptr)m_refs->decWeak(this);}
去调用weakref_impl的decWeak(),参数是wp的this,

void RefBase::weakref_type::decWeak(const void* id){//原子级操作减少弱引用计数,代码略if(弱引用!=1)return;  //弱引用没到0,就直接返回了 //如果走到这里,弱引用计数应该是为0,if(xxx)//如果对象不受弱引用控制{if(强引用==初始值)delete impl->mBase;  //干掉实际对象elsedelete impl;//农夫给干掉了}else{if(xxx) //如果既不受强引用控制也不受弱引用控制delete impl->mBase;//干掉实际对象}}


可以看出来,在函数先进行一次原子级操作,将弱引用计数-1之后。当弱引用计数==0的情况下,函数才回继续干活,否则函数立刻返回。wp的析构时是有可能干掉实际对象或者农夫impl的。


再来看看sp的析构函数

template<typename T>  sp<T>::~sp()  {if(m_ptr)m_ptr->decStrong(this);  }
根据多态,实际上调用的是RefBase的decStrong()

void RefBase::decStrong(const void *id)  {//原子级操作,减少强引用计数,代码略过if(xx) //如果强引用计数==0{if(不受弱引用控制)delete this; //干掉实际对象,因为m_pter调用的decStrong().this就是实际对象}refs->decWeak();  }


如果干掉实际对象,已知实际对象T是继承RefBase的类,则RefBase这个父类会率先析构,我们继续看看整个的析构流程

RefBase::~RefBase()  {if(mRefs->mWeak==0){delete mRefs;}  }

RefBase的析构函数中身,在满足条件的情况下将weakref_impl对象mRefs也一块干掉了。
  这个满足条件为什么是mRefs->mWeak==0,即弱引用计数为0呢?已知sp会令强引用+1&弱引用+1,而wp会令弱引用+1,
  当sp和wp一块使用时,有可能令弱引用数值 > 强引用数值,所以要判断一下,当强引用==0时,且弱引用==0才可以释放weakref_impl对象mRefs.
  此外在强引用==0的时候,依然有可能存在其他的弱指针通过weakref_impl在引用实际对象,所以必须弱引用==0才可以析构weakref_impl
  
  在decStrong()中为何又调用refs->decWeak()呢?
  

  我们再捋一下流程:

因为如果对象生命周期仅受到强引用计数控制,在decStrong()中会先干掉实际对象,而实际对象析构时跑到RefBase的析构中,顺带着把weakref_impl也给干掉了,

  皆大欢喜,农田农夫都没了,sp也没有了,实际对象也没有了,清理的很干净。虽然decWeak()在函数底部被调用,但是它不做事,进去就返回了。
  
  如果对象生命周期受到弱引用计数控制,则decStrong()中干掉实际对象的代码就不会得到执行,流程向下跑到decWeak()。 这时候decWeak()就不会立刻返回啦,它要做事,一旦发现弱引用也是0,强应用也是0,就会干掉实际对象,同上实际对象析构会顺带 析构RefBase,RefBase析构顺带析构weakref_impl,此时也是农田农夫没有了,wp自身也被析构没有了,实际对象也没有了,清理的也很干净。而 如果弱引用=0,而强引用有效,则仅仅干掉weakref_impl,实际对象的清理工作显然交给sp去操心了


很复杂很绕,分析的应该还不是很完整,但是学到不少,尤其是之前学类的时候,完全没有注意到的细节,很有帮助!