美文网首页
死磕源码系列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