经常会在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. win10下搭建jz2440v3(arm s3c2440)开发及gdb调试环境【转】

    本文转载自:https://blog.csdn.net/newjay03/article/details/72835758 本来打算完全在Ubuntu下开发的,但是水平有限,没有在Ubuntu下找到合 ...

  2. Elasticsearch之中文分词器

    前提 什么是倒排索引? Elasticsearch之分词器的作用 Elasticsearch之分词器的工作流程 Elasticsearch之停用词 Elasticsearch的中文分词器 1.单字分词 ...

  3. webservice使用注解修改WSDL内容

    首先看我们没有修改前的WSDL内容 此时服务端的类 修改后的 注解如下 package com.xiaostudy; import javax.jws.WebMethod; import javax. ...

  4. PRcurve

    https://blog.csdn.net/qq_33350808/article/details/83178002 问题:删掉pkl

  5. Java高级面试题

    一.基础知识: 1)集合类:List和Set比较,各自的子类比较(ArrayList,Vector,LinkedList:HashSet,TreeSet): 2)HashMap的底层实现,之后会问Co ...

  6. JavaScript高级程序设计-读书笔记(5)

    第13章 事件 1.事件流 事件流描述的是从页面中接收事件的顺序.IE的事件流是事件冒泡流,而Netscape Communicator的事件流是事件捕获流. (1)事件冒泡,即事件开始时由最具体的元 ...

  7. 【Python】学习笔记之列表生成式

    列表生成式 主要用于生成较为复杂的列表 常用用法 >>> [x * x for x in range(5) if x % 3 !=1 ] [0, 4, 9] #返回除以3余数不为1的 ...

  8. transform对定位元素的影响

    1.温故知新 absolute:生成绝对定位的元素,相对于除position:static 定位以外的第一个有定位属性的父元素进行定位,若父元素没有定位属性则相对于浏览器窗口的左上角定位,定位的元素不 ...

  9. ctci1.2

    ;     ; i < len/; i++){         tmp = *(str+i);         *(str+i) = *(str+len--i);         *(str+l ...

  10. kotlin for android----------MVP模式下(OKHttp和 Retrofit+RxJava)网络请求的两种实现方式

    今天要说的干货是:以Kotlin,在MVP模式下(OKHttp和 Retrofit+RxJava)网络请求两种实现方式的一个小案例,希望对大家有所帮助,效果图: Retrofit是Square公司开发 ...