当前位置: 首页 > news >正文

RefBase, sp和wp (1)

     RefBase是Android中所有对象的始祖,类似于MFC中的CObject,Java中的Object对象。在Android中,RefBase结合sp(strong pointer)和wp(weak pointer),实现来一套通过引用计数的方法来控制对象生命周期的机制。sp和wp存在的目的就是实现对new出来的内存自动回收。

1. RefBase和影子对象

    RefBase::RefBase() : mRefs (new weakref_impl(this)) {         // mRefs是RefBase的成员变量,类型为weakref_impl,称为影子对象。

    }

    weakref_impl是RefBase的内部类,继承于weakref_type。 RefBase::weakref_impl : RefBase::weakref_type 。

    weakref_impl::weakref_impl(RefBase* base)

         : mStrong(INITIAL_STRONG_VALUE),          // 强引用计数,初始值为0x1000000.

           mWeak(0),             // 若引用次数,初始值为0。

           mBase(base),            // 该影子对象指向的实际对象。

           mFlags(0),

           mStrongRefs(NULL) {

    }

    使用:

    class A :public RefBase {

    };

    A* pA = new A();

    此时, new了一个A对象后,实际上还new了一个weakref_impl对象,称这个weakref_impl对象为影子对象,A为实际对象。

2. sp

构造:

    接着上面,定义一个sp:

    sp<A> spA(pA);

    (1) sp是一个模板类,定义如下:

    template<typename T>

    sp<T>::sp(T* other) : m_ptr(other) {    // other即之前创建的pA.

        if (other) {

            other->incStrong(this);

        }

    }

    (2) incStrong()函数的实现:

    void RefBase::incStrong(const void* id) const {

        weakref_impl* const refs = mRefs;

        // 操作影子对象, 增加强/弱 引用计数。

        refs->incWeak(id);

        const int32_t  c = android_atomic_inc(&refs->mStrong);     //为原子执行+1操作,并返回旧值。影子对象强引用计数加1.

        if (c != INITIAL_STRONG_VALUE) {

               return;            //  若c不是初始,则表明这个对象已经被强引用过一次了。

        }

        android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);   // 原子加操作。即执行了 refs->mStrong + (-0x1000000), 结果mStrong = 1.

       // 如果是第一次引用, 则调用onFirstRef, 派生类可以重载这个函数完成一些初始化工作。

        const_cast<RefBase*>(this)->onFirstRef();

    }

    (3) incWeak()函数的实现:

    void RefBase::weakref_type::incWeak(const void* id) {

             weakref_impl* const impl = static_cast<weakref_impl*>(this);

             const int32_t c = android_atomic_inc(&impl->mWeak);      // 影子对象弱引用计数加1.

    }

    sp的构造,使RefBase中影子对象的强引用计数变为1, 弱引用计数也变为1.

析构:

    (1) 析构函数:

    template<typename T>

    sp<T>::~sp() {

        if (m_ptr)  {

            m_ptr->decStrong(this);      // 调用实际对象的decStrong, 有RefBase实现。      

        }

    }

    (2) decStrong函数的实现:

    void RefBase::decStrong(const void* id) const {

        weakref_impl* const refs = mRefs;                   // 临时保存影子对象。

        const int32_t c = android_atomic_dec(&refs->mStrong);

        if (c == 1) {

            const_cast<RefBase*>(this)->onLastStrongRef(id);     // 调用onLastStrongRef, 表明强引用计数减为0, 对象可能被delete。

            if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {

                delete this;            // 干掉实际对象,影子对象mRef并没有被干掉,被保存到refs了。

            }

             refs->decWeak(id);        // 调用影子对象的decWeak.

        }

    }

    注意:delete this 会导致A的析构函数被调用,从而RefBase的析构函数也被调用。

            RefBase::~RefBase() {

                if (mRef->mWeak == 0) {       // 若弱引用计数不为0, 影子对象不会被析构。

                    delete mRefs;

                }

            }

3. wp

构造:

    使用已有sp, 定义一个wp:

    wp<A> wpA(spA);

    (1) wp有多个构造函数,看一下参数为sp的这个:

    template<typename T>

    wp<T>::wp(const sp<T>& other) : m_ptr(other.m_ptr) {               // wp的m_ptr指向实际对象

        if (m_ptr) {

            m_refs = m_ptr->createWeak(this);                                      // 调用pA的creakWeak, 并保存返回值到成员变量m_refs中。

        }

    }

    (2) creakWeak的实现:

    RefBase::weakref_type* RefBase::createWeak(const void* id) const {

       mRefs->incWeak(id);            // 调用影子对象的incWeak,弱影用计数加1.

       retrun mRefs;                     //返回影子对象本身。

    }

    wp构造后,影子对象的弱应用计数增加1.

    注意: wp中有两个成员变量:m_ptr保存实际对象,m_refs保存影子对象。

             sp只有一个成员变量:m_ptr保存实际对象,但该实际对象已包含对应的影子对象。

析构:

    (1) 析构函数:

    template<T>

    wp<T>::~wp() {

        if (m_ptr) {

            m_refs->decWeak(this);                 // 调用影子对象的decWeak.

        }

    }

    (2) decWeak()函数实现:

    void RefBase::weakref_type::decWeak(const void* id) {

        weakref_impl* const impl = static_cast<weakref_impl*>(this);

        const inst32_t c android_atomic_dec(&impl->mWeak);           // 原子减1,返回旧值。

        if (c != 1) {      // 旧值 >=2 , 直接返回。

            return;

        }

        // 若c = 1, 则弱引用计数为0, 说明没有弱引用指向实际对象了,考虑是否释放内存。

        if ((impl->mFlag&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {

            if (impl->mStrong == INITIAL_STRONG_VALUE) {

                  delete impl->mBase;                                     // 强引用计数也为0, 释放实际对象。

           } else {

                  delete impl;                                                  // 否则,impl就是this, 释放影子对象。

           }

        } else {

             impl->mBase->onLastWeakRef(id);

             if ((impl->mFlogs&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {

                 delete impl->mBase;

             }

        }

    }

转载于:https://www.cnblogs.com/Jackwen/p/4332120.html

相关文章:

  • 数据库设计经验谈
  • CSS3使用calc()做算术 (转)
  • 【转】linux 中dd命令使用详解
  • lanmp v2.3一键安装包发布(包括lamp,lnmp,lnamp安装)
  • 安装wampserver时提示丢失MSVCR110.dll
  • android 让一个Activity停留几秒后再跳转
  • Formweaver简介
  • 【大数加法】POJ-1503、NYOJ-103
  • MySQL锁机制总结(二)
  • CentOS 7关闭图形桌面开启文本界面
  • excel VLOOKUP函数的用法
  • ubuntu 查看和关闭端口
  • LCS最长公共子序列java实现
  • 正则表达式的概述
  • 防止APK反编译和二次加密
  • CSS中外联样式表代表的含义
  • docker容器内的网络抓包
  • java多线程
  • Joomla 2.x, 3.x useful code cheatsheet
  • js数组之filter
  • js中的正则表达式入门
  • nodejs调试方法
  • 将 Measurements 和 Units 应用到物理学
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 理解在java “”i=i++;”所发生的事情
  • 实战|智能家居行业移动应用性能分析
  • 收藏好这篇,别再只说“数据劫持”了
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 数组大概知多少
  • Semaphore
  • ​ 无限可能性的探索:Amazon Lightsail轻量应用服务器引领数字化时代创新发展
  • ​一些不规范的GTID使用场景
  • # 20155222 2016-2017-2 《Java程序设计》第5周学习总结
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • #Linux(权限管理)
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (附源码)php投票系统 毕业设计 121500
  • (附源码)基于SSM多源异构数据关联技术构建智能校园-计算机毕设 64366
  • (三分钟)速览传统边缘检测算子
  • (三分钟了解debug)SLAM研究方向-Debug总结
  • (学习日记)2024.01.09
  • (转)拼包函数及网络封包的异常处理(含代码)
  • .gitignore文件设置了忽略但不生效
  • .net 中viewstate的原理和使用
  • .NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)
  • .NET分布式缓存Memcached从入门到实战
  • // an array of int
  • /etc/sudoers (root权限管理)
  • @angular/cli项目构建--Dynamic.Form
  • @entity 不限字节长度的类型_一文读懂Redis常见对象类型的底层数据结构
  • @Transient注解
  • [22]. 括号生成
  • [Android] Amazon 的 android 音视频开发文档
  • [Android开源]EasySharedPreferences:优雅的进行SharedPreferences数据存储操作
  • [BT]BUUCTF刷题第8天(3.26)