经常会在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. PHP的memory_limit引起的问题

    在运行PHP程序,通常会遇到下面的错误, 这个意味着PHP脚本使用了过多的内存,并超出了系统对其设置的允许最大内存.解决这个问题,首先需要查看你的程序是否分配了过多的内存,在程序没有问题的情况下,你可 ...

  2. mybatis中的映射类型

  3. java httpUtil

    public class HttpUtils { public static String getContent(String url, Map<String, String> heads ...

  4. Css常用属性单位

    长度单位:px-像素 颜色单位:         ①十六进制:#FFFFFF:         ②颜色名称:red:         ③RGB颜色代码:RGB(0-255,0-255,0-255): ...

  5. CBT怎样进行注册

    CBT币未来升值千倍?揭秘为何比特云币注册认证送矿机? 比特云币先机先机,1月6号准备启动,虚拟货币新宠云比特(Cloud Bit 简称CBT)将于近日强势登陆交易市场.这款由全球最大的比特矿工联盟发 ...

  6. [解决]JS失效,提示HTML1114: (UNICODE 字节顺序标记)的代码页 utf-8 覆盖(META 标记)的冲突的代码页 utf-8

    上网找了找,木有找到相关的解决办法,索性自己试了试. 原页面是这样写的: <html> <head> <meta http-equiv="Content-Typ ...

  7. Math.Round 四舍五入问题 解惑 !

    前言: 一定要说 坑爹的微软! 坑爹的微软! 坑爹的微软!  重要的事情说 三遍 ! 摘录 SMDN 示例 下面的示例演示就近舍入. C# C++ VB   Math.Round(3.44, 1); ...

  8. python ConfigParse模块(转)

    最近写程序要用到配置文件,那么配置文件的解析就很重要了,下文转自chinaunix 一.ConfigParser简介 ConfigParser 是用来读取配置文件的包.配置文件的格式如下:中括号“[ ...

  9. linux一键修改mysql密码脚本

    乱七八糟的shell脚本大集合 #!/bin/bash mysql_root_pwd=$( ; echo) mysql_cnf_path=$ export mysql_passwd=$mysql_ro ...

  10. vue element new vue const

    new Vue{ el:"app", } ========= const app = new Vue({ router, data:{....} }).$mount('#app') ...