美文网首页
死磕源码系列3——智能指针

死磕源码系列3——智能指针

作者: 徒步青云 | 来源:发表于2020-11-10 16:17 被阅读0次

    参照罗升阳的《Android源代码情景分析第三版》,自己重新分析一遍Android P上的智能指针,加强对基础知识的理解。

    一、总览

    由于Android底层是采用C/C++语言编写,它没有像java类似的垃圾回收机制,所以就需要程序员去手动释放释放内存,但随着项目规模变大,手动释放内存这种方式耗时耗力,且极不靠谱,这时候就需要用到智能指针。

    根据我个人理解,智能指针分为两种:轻量级指针重量级指针

    注意:这里我将强指针弱指针统称为重量级指针,只是为了便于大家理解,因为它们之间存在千丝万缕的联系,不便于独立讲解。

    其大致区别如下表所示:

    轻量级指针 重量级指针
    模板类 sp<T> sp<T>和wp<T>
    模板参数T 继承至LightRefBase 继承至RefBase
    计数器 LightRefBase->mCount RefBase->mRefs(mWeak、mStrong两个引用计数)
    计数器何时释放 无需释放 弱引用计数(mRefs->mWeak)为0时
    对象何时释放 mCount==0 1、对象生命周期受强引用影响,且mRefs->mStrong==0
    2、对象生命周期受强、弱引用同时影响时,且mRefs->mWeak==0

    这里需要注意:
    1、智能指针并不是指针,而是一个模板类。
    2、强指针增加(减少)强引用计数(mStrong)时,也会相应增加(减少)弱引用计数(mWeak)。
    3、弱指针只会增加(减少)弱引用计数(mWeak)。

    由2、3点可以看出,mRefs->mWeak总是大于等于mRefs->mStrong。

    3、强/弱指针有一些生命周期,当对象被强指针引用时,该对象一定存在。但当对象只被弱指针引用时,根据其生命周期,该对象有可能被释放。

    二、轻量级指针

    template <class T>
    class LightRefBase
    {
    public:
        inline LightRefBase() : mCount(0) { }
        inline void incStrong(__attribute__((unused)) const void* id) const {
            mCount.fetch_add(1, std::memory_order_relaxed);
        }
        inline void decStrong(__attribute__((unused)) const void* id) const {
            if (mCount.fetch_sub(1, std::memory_order_release) == 1) {
                std::atomic_thread_fence(std::memory_order_acquire);
                delete static_cast<const T*>(this);
            }
        }
        inline int32_t getStrongCount() const {
            return mCount.load(std::memory_order_relaxed);
        }
    
    private:
        mutable std::atomic<int32_t> mCount;
    };
    

    轻量级指针采用atomic<int32_t> mCount进行指针计数。其模板类为sp<>,当调用以下语句时,mCount将自增,而当sp<>脱离作用域,系统自动回收时(sp是通过赋值操作,而不是new获得)。

    LightClass *p = new LightClass();  //LightClass继承至LightBRefBase
    sp<LightClass> pRef1 = p;
    sp<LightClass> pRef2 = pRef1;
    

    待续(一天写一点)

    void RefBase::weakref_type::decWeak(const void* id)
    {
        weakref_impl* const impl = static_cast<weakref_impl*>(this);
        const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
        if (c != 1) return;
        atomic_thread_fence(std::memory_order_acquire);
    
        int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            if (impl->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
                ALOGW("RefBase: Object at %p lost last weak reference "
                        "before it had a strong reference", impl->mBase);
            } else {
                delete impl;
            }
        } else {
            impl->mBase->onLastWeakRef(id);
            delete impl->mBase;
        }
    }
    
    RefBase::RefBase()
        : mRefs(new weakref_impl(this))
    {
    }
    
    RefBase::~RefBase()
    {
        int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
        if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
            if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
                delete mRefs;
            }
        } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
            delete mRefs;
        }
    
        const_cast<weakref_impl*&>(mRefs) = NULL;
    }
    

    RefBase在构造函数中,将创建weakref_impl对象,并赋值给mRefs。

    重量级指针

    重量级指针分析比轻量级指针要难理解很多,这样按一定方法去分析,才能不迷失方向。
    宗旨:时刻关心对象和计数器何时被释放

    相关文章

      网友评论

          本文标题:死磕源码系列3——智能指针

          本文链接:https://www.haomeiwen.com/subject/dxxqictx.html