经常会在android的framework代码中发现sp<xxx>和wp<xxx>这样的指针,平时看的时候都把他当成一个普通的指针封装过掉了,这几天终于忍不住了,想深入了解一下。

相关的代码:

frameworks/base/include/utils/RefBase.h

frameworks/base/libs/utils/RefBase.cpp

sp和wp都是一个模板类,看一下sp类的定义:

  1. template <typename T>
  2. class sp
  3. {
  4. public:
  5. typedef typename RefBase::weakref_type weakref_type;
  6. inline sp() : m_ptr(0) { }
  7. sp(T* other);
  8. sp(const sp<T>& other);
  9. ~sp();
  10. ......
  11. private:
  12. // Optimization for wp::promote().
  13. sp(T* p, weakref_type* refs);
  14. T*              m_ptr;
  15. };

可以看到他确实封转了一个原生指针T* m_ptr. 再看一下其中一个构造函数和析构函数:

  1. template<typename T>
  2. sp<T>::sp(T* other)
  3. : m_ptr(other)
  4. {
  5. if (other) other->incStrong(this);
  6. }
  7. template<typename T>
  8. sp<T>::~sp()
  9. {
  10. if (m_ptr) m_ptr->decStrong(this);
  11. }

咋一看好奇怪,因为在构造函数中调用了incStrong(),在析构函数中调用的decStrong(),显然是管理引用计数的函数,但是sp类的中并没有定义这两个函数,这两个函数是在RefBase类中定义的,由此可以得出结论:

要想使用sp<T>或者wp<T>, T必需要继承RefBase类才行

RefBase的静态关系如下:

其中weakref_type是RefBase的内嵌类,weakref_impl则是weakref_type的子类,RefBase的大部分 工作都是交由weakref_impl类来完成,通过RefBase的成员变量weakref_impl* const mRefs。查看其中一个sp的构造函数:

  1. template<typename T>
  2. sp<T>::sp(T* other)
  3. : m_ptr(other)
  4. {
  5. if (other) other->incStrong(this);
  6. }

建立sp<xxx>的动态关系如下:

sp<T>

--> RefBase : incStrong()

-->weakref_impl : addStrongRef()

-->android_atomic_inc(&refs->mStrong)

可见当一个普通指针变成一个sp指针后,将会由RefBase类维护该指针的引用计数,当引用为零时则自动释放该指针指向的内存:

  1. void RefBase::decStrong(const void* id) const
  2. {
  3. weakref_impl* const refs = mRefs;
  4. refs->removeStrongRef(id);
  5. const int32_t c = android_atomic_dec(&refs->mStrong);
  6. if (c == 1) {
  7. const_cast<RefBase*>(this)->onLastStrongRef(id);
  8. if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
  9. delete this;    //引用为0,销毁
  10. }
  11. }
  12. refs->removeWeakRef(id);
  13. refs->decWeak(id);
  14. }

wp<xxx>是怎么一回事?

wp其实是弱指针的意思,wp<T>类型不能直接对类型T进行操作,要想对T进行某种操作,必需把wp升级为sp指针,使用promote()来实现升级:

wp<T> weakp= new T();

sp<T> t = weakp.promote();

wp可能会在弱引用计数不为0的情况下被销毁,执行如下代码:

  1. class WPTest : public RefBase {
  2. public:
  3. WPTest(){
  4. LOGD("WPTest constructor");
  5. }
  6. virtual ~WPTest() {
  7. LOGD("WPTest destructor");
  8. }
  9. virtual void onFirstRef() {
  10. LOGD("first weak ptr ref callback");
  11. }
  12. virtual void onLastStrongRef(const void* id) {
  13. LOGD("last strong ptr ref callback");
  14. }
  15. virtual void onLastWeakRef(const void* id) {
  16. LOGD("last weak ptr ref callback");
  17. }
  18. };
  19. int main()
  20. {
  21. WPTest *T = new WPTest();
  22. {
  23. wp<WPTest> weakp(T);
  24. {
  25. LOGD("promote to strong ptr.../n");
  26. sp<WPTest> strongp = weakp.promote();
  27. LOGD("strong ptr's lifetime is just about to finish .../n");
  28. }
  29. LOGD("weak ptr's lifetime is just about to finish .../n");
  30. }
  31. LOGD("weak ptr is out of scope./n");
  32. return 0;
  33. }

程序打印的结果是:

D/sp-wp-sample(  225): WPTest constructor
D/sp-wp-sample(  225): promote to strong ptr...
D/sp-wp-sample(  225): first weak ptr ref callback
D/sp-wp-sample(  225): strong ptr's lifetime is just about to finish ...
D/sp-wp-sample(  225): last strong ptr ref callback
D/sp-wp-sample(  225): WPTest destructor
D/sp-wp-sample(  225): weak ptr's lifetime is just about to finish ...
D/sp-wp-sample(  225): weak ptr is out of scope.

由此可见虽然wp<WPTest >的生命周期还没有结束,但是因为升级为sp<WPTest
>后,sp<WPTest >的强引用计数为0,导致WPTest 被销毁,当强引用为0而弱引用不为0时,WPTest
销毁时,基类RefBase的mRefs指向的weakref_impl类并没有释放,从而保证了弱引用可以继续起作用,这点可以从RefBase的析构
函数中看出来:

  1. RefBase::~RefBase()
  2. {
  3. //    LOGV("Destroying RefBase %p (refs %p)/n", this, mRefs);
  4. if (mRefs->mWeak == 0) {
  5. //        LOGV("Freeing refs %p of old RefBase %p/n", mRefs, this);
  6. delete mRefs;
  7. }
  8. }

不过也可以改变这一行为,我们修改一下WPTest的构造函数:

  1. WPTest(){
  2. LOGD("WPTest constructor");
  3. extendObjectLifetime(OBJECT_LIFETIME_WEAK);
  4. }

这时的打印结果是:

D/sp-wp-sample(  217): WPTest constructor
D/sp-wp-sample(  217): promote to strong ptr...
D/sp-wp-sample(  217): first weak ptr ref callbac
D/sp-wp-sample(  217): strong ptr's lifetime is j
D/sp-wp-sample(  217): last strong ptr ref callba
D/sp-wp-sample(  217): weak ptr's lifetime is j
D/sp-wp-sample(  217): last weak ptr ref callback
D/sp-wp-sample(  217): WPTest destructor
D/sp-wp-sample(  217): weak ptr is out of scope.

可以看出现在只有当强引用和弱引用的计数都为0时,WPTest对象才会被销毁。

转自:http://blog.csdn.net/DroidPhone/article/details/5799792

Android中的sp和wp指针的更多相关文章

  1. Android中的sp与wp

    一.相关code文件 二.code具体分析 lightrefebase: refbase: sp: wp: flag: 三.使用注意事项 不能在把目标对象赋给一个长久存在的sp对象之前赋给一个短生命周 ...

  2. android RefBase、sp、wp

    首先RefBase在android的c++部分是作为一个所有类的基类,其作用跟Java中的Object类似 这个类中存在一个私有成员: weakref_impl* const mRefs;(weakr ...

  3. Android 内核初识(7)RefBase、LightRefBase、sp和wp

    简介 RefBase是Android中所有对象的始祖,类似MFC中的CObject及Java中的Object对象.在Android中,RefBase结合sp和wp,实现了一套通过引用计数的方法来控制对 ...

  4. android中dx、dp、dip、sp单位的区别

    1.dp=dip 2.px基于像素,后两者基于像素密度. 3.px既可用于宽度高度,也可用于字体,dp用于宽高,sp用于字体4.android中以320*480屏幕为基准.在相同值的px和dp,在32 ...

  5. Android中dip、dp、sp、pt和px的区别

    1.概述 过去,程序员通常以像素为单位设计计算机用户界面.例如:图片大小为80×32像素.这样处理的问题在于,如果在一个每英寸点数(dpi)更高的新显示器上运行该程序,则用户界面会显得很小.在有些情况 ...

  6. android中像素单位dp、px、pt、sp的比较

    dp(dip): device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA.HVGA和QVGA 推荐使用这个,不依赖 ...

  7. Android中px, ppi, dpi, dp, dip, sp概念解析

    Android中px, ppi, dpi, dp, dip, sp概念解析

  8. android中dip、dp、px、sp和屏幕密度

    1. dip: device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA.HVGA和QVGA 推荐使用这    这个 ...

  9. Android中dip, dp, px,pt, sp之间的区别:

    Android中dip.dp.sp.pt和px的区别   1.概述 过去,程序员通常以像素为单位设计计算机用户界面.例如:图片大小为80×32像素.这样处理的问题在于,如果在一个每英寸点数(dpi)更 ...

随机推荐

  1. 爬虫框架Scrapy之详解

    Scrapy 框架 Scrapy是用纯Python实现一个为了爬取网站数据.提取结构性数据而编写的应用框架,用途非常广泛. 框架的力量,用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页 ...

  2. LeetCode——Increasing Triplet Subsequence

    Question Given an unsorted array return whether an increasing subsequence of length 3 exists or not ...

  3. 转:eclipse与myeclipse恢复已删除的文件和代码

  4. Flask-最简单的Python http服务框架使用

    环境准备 Python + pip + Flask sudo easy_install pip sudo pip install flask 代码如下(做了个jieba分词的服务) # encodin ...

  5. Bellman-Ford FORMCM

    Bellman-Ford date: 2018/2/2 author:pprp theme:Dijstra 简介 单源最短路问题 要求: 图中不能出现负圈 思路: Bellman-Ford算法就是遍历 ...

  6. Dropping water balloons (入门dp)

    2017-08-12 18:36:24 writer:pprp 最近刚刚接触动态规划,感觉状态的查找和转移自己很难想到,都是面向题解编程,但是一开始都是这样了,只有相信我可以独立自己解决动态规划这类问 ...

  7. sa learning

    后缀数组之前一直在给队友搞,但是这个类太大了,预感到青岛八成会有,于是自己也学习一下,记录一下做题的历程 所用的模板暂时来自于队友的倍增nlogn da算法 int t1[maxn] , t2[max ...

  8. MATLAB 2014a (8.3) Compiler Runtime (MCR)

    在安装的时候可以 ./install -H 界面化安装到自己目录下 MATLAB 2014a (8.3) Runtime Compiler (MCR) Errors when trying to la ...

  9. 分享几道Java线程面试题

    不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员的欢迎.大多数待遇丰厚的Java开发职位都要求开发者精通多线程 ...

  10. 谈一谈最近关闭的Kindle人论坛

    最近Kindle圈子内最大的论坛“Kindle人”关闭了,倒也掀起了一阵小波澜.Kindle人论坛是K友圈子里比较著名的一个“Kindle资源分享论坛”,这么一说其实混了这么久网络,大家都知道这个论坛 ...