经常会在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. JSON 中JsonConfig的使用(转)

    我们通常对一个Json串和Java对象进行互转时,经常会有选择性的过滤掉一些属性值,而json-lib包中的JsonConfig为我们提供了这种 功能,具体实现方法有以下几种.(1)建立JsonCon ...

  2. mysql对数据库的备份和还原

    在对mysql数据库的某个数据库进行备份时,使用 mysqldump命令来进行操作 mysqldump -u root -p db_database_name > /[your_path.mys ...

  3. 通过Fiddler进行手机抓包

    通过Fiddler进行手机抓包 通过Fiddler抓包工具,可以抓取手机的网络通信,但前提是手机和电脑处于同一局域网内(WI-FI或热点),然后进行以下设置: 用Fiddler对Android应用进行 ...

  4. c#的逆向工程-IL指令集

    一些 IL 语言解释:  跳转指令集合 Public field Static     Beq     如果两个值相等,则将控制转移到目标指令. Public field Static     Beq ...

  5. MongoDB 副本集和C#交互,简单测试

    MongoDB 副本集和C#交互,简单测试 primary节点宕机: 模拟primary节点宕机的情况,这时查看监控: 可以看到37018已经成了primary节点.主界面宕机导致了整个集群发生一次e ...

  6. HDU 1698 just a hook - 带有lazy标记的线段树(用结构体实现)

    2017-08-30 18:54:40 writer:pprp 可以跟上一篇博客做个对比, 这种实现不是很好理解,上一篇比较好理解,但是感觉有的地方不够严密 代码如下: /* @theme:segme ...

  7. finally是否执行?finally何时执行?

    一.finally是否执行: 1.只有与 finally 相对应的 try 语句块得到执行的情况下,finally 语句块才会执行当finally 相对应的 try 语句块之前,已经抛出错误,或者已经 ...

  8. [Eclipse]保存java文件时,自动删除不需要的包import

    1.修改设定:Window->Preferences 2.效果:                =>           

  9. Burpsuite的简单应用-y-Proxy

    打开burpsuite:Proxy功能 一.进入Proxy页面,代理设置 将浏览器的代理地址设置一样: 之前没有代理,直接添加,有的话,可以勾选就好了:不同浏览器,设置位置不一致,百度参考 二.执行: ...

  10. Android数据库框架-----ORMLite 的基本用法

    ORMLite 是一款非要流行的Android平台上的数据库框架,性能优秀,代码简洁: 简述: 优点: 1.轻量级:2.使用简单,易上手:3.封装完善:4.文档全面. 缺点:1.基于反射,效率较低(本 ...