Android13 智能指针sp wp refbase

1 sp介绍

智能指针(Smart Pointer)是一种用于管理动态分配的内存资源的工具,Android 提供了名为 sp 的智能指针类,也被称为强引用指针,用法和c++指针是一样的,但是sp指针可以根据引用计数来动态管理内存资源,普通指针则只能通过delete来释放内存资源

2 sp的使用

eg:

cpp
#include <utils/RefBase.h>

using namespace android;

class MyClass : public RefBase {
    // ...
};

int main() {
    sp<MyClass> obj = new MyClass();

    // 使用 obj 智能指针来管理动态分配的对象

    return 0;
}

1 这里的main函数我们创建了sp类型对象,属于栈对象,在作用域结束位置,会被自动释放
2 Myclass对象继承与RefBase类,RefBase是所有对象的基类,用于管理引用计数

3 sp的原理

抛出俩个问题
1 如何管理引用计数
2 如何通过引用计数判断引用的开始和结束
上述代码中我们构造了sp类型的栈对象

3.1 sp构造函数
StrongPointer.h
template<typename T>
class sp {

template<typename T>
sp<T>::sp(T* other)
        : m_ptr(other) {
    //sp类型对象构造函数 other不为空,赋值给m_ptr
    //m_ptr会引用other指向的堆内存对象
    if (other) {
        check_not_on_stack(other);
        //other指针指向的对象,基础refbase 
        //调用refbase的incStrong this指sp
        other->incStrong(this);
    }
}
}

可以看到sp是一个模板类,这里我们设置T为MyClass,首先会将指向MyClass的堆对象指针赋值给m_ptr,由此m_ptr也会引用MyClass的堆对象,调用other->incStrong(this)方法,增加引用计数,通过上述方法,我们知道在构造函数时会对引用计数进行增加,接下来分析引用计数的增加流程

3.2 RefBase::incStrong

other是Myclass对象的指针,Myclass继承与RefBase,incStrong是RefBase基类的方法

RefBase.cpp

void RefBase::incStrong(const void* id) const
{
    //refs指向weakref_impl类型对象
    weakref_impl* const refs = mRefs;
    //将当前运行环境的标识符(id)加入到其弱引用计数器中
    refs->incWeak(id);

    refs->addStrongRef(id);
    //使用原子操作将refs->mStrong+1返回旧值
    const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
    ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
#if PRINT_REFS
    ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    if (c != INITIAL_STRONG_VALUE)  {
        //检查c不等于INITIAL_STRONG_VALUE 代表不是第一次引用
        return;
    }

    int32_t old __unused = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE, std::memory_order_relaxed);
    // A decStrong() must still happen after us.
    ALOG_ASSERT(old > INITIAL_STRONG_VALUE, "0x%x too small", old);
    //第一次引用,执行初始化操作
    refs->mBase->onFirstRef();
}

void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id);
    //原子操作将impl->mWeak +1
    const int32_t c __unused = impl->mWeak.fetch_add(1,
            std::memory_order_relaxed);
    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}

在执行RefBase::incStrong,会让强引用计数器加1,弱引用计数器也会加1

3.3 sp析构

在前面我们构建了sp对象类型是MyClass,在sp对象作用域结束时,会调用sp对象的析构函数

StrongPointer.h
template<typename T>
sp<T>::~sp() {
    if (m_ptr)
    //如果m_ptr存在则减少引用计数
        m_ptr->decStrong(this);
}

void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    //将标识符id移除强引用计数器
    refs->removeStrongRef(id);
    //执行原子操作减少refs->mStrong的值
    const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
#if PRINT_REFS
    ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    LOG_ALWAYS_FATAL_IF(BAD_STRONG(c), "decStrong() called on %p too many times",
            refs);
    if (c == 1) {
        //case1 如果返回的旧值是1,则代表这次析构后该对象将没有人引用
        std::atomic_thread_fence(std::memory_order_acquire);
        refs->mBase->onLastStrongRef(id);
        int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            //这里获取flags与OBJECT_LIFETIME_MASK与运算如果是强指针
            //会执行delete从堆中释放该对象
            delete this;
            // The destructor does not delete refs in this case.
        }
    }
    // Note that even with only strong reference operations, the thread
    // deallocating this may not be the same as the thread deallocating refs.
    // That's OK: all accesses to this happen before its deletion here,
    // and all accesses to refs happen before its deletion in the final decWeak.
    // The destructor can safely access mRefs because either it's deleting
    // mRefs itself, or it's running entirely before the final mWeak decrement.
    //
    // Since we're doing atomic loads of `flags`, the static analyzer assumes
    // they can change between `delete this;` and `refs->decWeak(id);`. This is
    // not the case. The analyzer may become more okay with this patten when
    // https://bugs.llvm.org/show_bug.cgi?id=34365 gets resolved. NOLINTNEXTLINE
    //通过原子操作减少弱引用计数
    refs->decWeak(id);
}

void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->removeWeakRef(id);
    //执行原子操作减少impl->mWeak的值
    const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
    LOG_ALWAYS_FATAL_IF(BAD_WEAK(c), "decWeak called on %p too many times",
            this);
    //如果c != 1代表当前对象还在被引用中
    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) {
        //如果是强指针引用对象
        // This is the regular lifetime case. The object is destroyed
        // when the last strong reference goes away. Since weakref_impl
        // outlives the object, it is not destroyed in the dtor, and
        // we'll have to do it here.
        if (impl->mStrong.load(std::memory_order_relaxed)
                == INITIAL_STRONG_VALUE) {
            //强引用控制,但是实际对象构造出来,没有被强引用引用过

            // Decrementing a weak count to zero when object never had a strong
            // reference.  We assume it acquired a weak reference early, e.g.
            // in the constructor, and will eventually be properly destroyed,
            // usually via incrementing and decrementing the strong count.
            // Thus we no longer do anything here.  We log this case, since it
            // seems to be extremely rare, and should not normally occur. We
            // used to deallocate mBase here, so this may now indicate a leak.
            //这是一种异常情况,一般不会存在强引用没有,弱引用还存在
            ALOGW("RefBase: Object at %p lost last weak reference "
                    "before it had a strong reference", impl->mBase);
        } else {
            //case2 至少存在一个强引用情况下
            //释放引用计数器对象
            // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
            delete impl;
        }
    } else {
        // This is the OBJECT_LIFETIME_WEAK case. The last weak-reference
        // is gone, we can destroy the object.
        //弱引用控制 执行onLastWeakRef回调
        impl->mBase->onLastWeakRef(id);
        //释放实际对象
        delete impl->mBase;
    }
}

m_ptr->decStrong来调用refbase的decStrong减少引用计数
再通过原子操作处理完mStrong引用计数器后,根据返回的旧值c
来判断当前是否为最后一次强引用
·不是的话就正常调用 refs->decWeak(id),尝试对弱引用计数器mWeak进行原子操作
是的话执行mBase->onLastStrongRef(id),执行最后一次引用的回调
再去delete对象,释放内存
也会执行 refs->decWeak(id)方法对弱引用计数器mWeak进行原子操作,判断当前是否为最后一次弱引用
是的话,检查flags是强引用控制还是弱引用控制
强引用控制的话
首先会判断case1 mStrong == INITIAL_STRONG_VALUE
这代表没有强引用引用过该对象,但是确存在弱引用,这属于异常情况会打印log提示
case2 mStrong != INITIAL_STRONG_VALUE 代表至少存在一个强引用情况下,那么会删除引用计数器对象
弱引用控制的话
那就执行 impl->mBase->onLastWeakRef(id)方法触发回调
delete实际对象释放内存
在sp最后一个引用下,释放实际对象后,会自动调用RefBase的析构函数

RefBase::~RefBase()
    int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
    // Life-time of this object is extended to WEAK, in
    // which case weakref_impl doesn't out-live the object and we
    // can free it now.
    if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
        //flag为弱指针控制
        // It's possible that the weak count is not 0 if the object
        // re-acquired a weak reference in its destructor
        //读取mWeak的值为0,表示没有任何弱引用指向对象,那么它会删除 mRefs 对象,即释放引用计数器对象的内存
        if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
            delete mRefs;
        }
    } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
        // We never acquired a strong reference on this object.
        //flag为强指针控制 但是没有强引用引用过的异常情况,打印log
        // TODO: make this fatal, but too much code in Android manages RefBase with
        // new/delete manually (or using other mechanisms such as std::make_unique).
        // However, this is dangerous because it's also common for code to use the
        // sp<T>(T*) constructor, assuming that if the object is around, it is already
        // owned by an sp<>.
        ALOGW("RefBase: Explicit destruction, weak count = %d (in %p). Use sp<> to manage this "
              "object.",
              mRefs->mWeak.load(), this);

#if CALLSTACK_ENABLED
        CallStack::logStack(LOG_TAG);
#endif
    }
    // For debugging purposes, clear mRefs.  Ineffective against outstanding wp's.
    //设置mRefs为空指针 防止野指针出现
    const_cast<weakref_impl*&>(mRefs) = nullptr;
}

在处理refbase的析构时,根据flag判断当前是弱引用控制还是强引用控制
弱引用控制当引用计数器的mWeak等于0时,可以delete引用计数器对象
强引用控制但是确从来没有强引用引用过的异常情况,会打印log
最后将mRefs指针置空防止野指针出现
回到上面我们提到的例子

#include <utils/RefBase.h>

using namespace android;

class MyClass : public RefBase {
    // ...
};

int main() {
    sp<MyClass> obj = new MyClass();

    // 使用 obj 智能指针来管理动态分配的对象

    return 0;
}

1 首先构造实际对象
2 先执行refbase的构造在执行sp的构造
3 执行incStrong方法先增加mweak弱引用计数再增加mstrong强引用计数
4 根据旧值判断是否第一次引用对象,触发onFirstRef回调
5 作用域结束,执行sp的析构函数
6 执行refbase的decStrong,根据原子操作减少mStrong强引用计数
7 根据旧值判断当前是否为最后一次强引用
8 是的话触发onLastStrongRef回调,释放实际对象
9 执行 refs->decWeak(id),减少mWeak弱引用计数
10 根据旧值确认是否为最后一次弱引用
11 是的话删除引用计数器对象
12执行父类refbase的析构函数,获取flag确认当前时强引用控制
13 mRefs置为空指针来防止野指针出现

4 wp的原理

因为sp在构造和析构时都会影响到弱引用计数器,所以下面内容会和sp有重复,只要明白了sp的原理,wp也很好理解

4.1 wp的例子
class MyClass : public RefBase {
    // ...
};

int main() {
 MyClass* myClass = new MyClass();
     sp<MyClass> obj = new MyClass();
    wp<MyClass> weakObj(obj);    // 使用 obj 智能指针来管理动态分配的对象
    return 0;
}

这里先指向sp的对象放入wp的构造函数中

4.2 wp的构造
RefBase.h
template<typename T>
wp<T>::wp(const sp<T>& other)
    : m_ptr(other.m_ptr)
{
    //指向m_ptr->createWeak(this)
    m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
}


RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
    //指向mRefs->incWeak(id);
    mRefs->incWeak(id);
    return mRefs;
}

void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id);
    //原子操作将impl->mWeak +1
    const int32_t c __unused = impl->mWeak.fetch_add(1,
            std::memory_order_relaxed);
    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}

可以看到在弱引用的构造中只会通过原子操作调整mWeak的值

4.3 wp的析构
RefBase.h
template<typename T>
wp<T>::~wp()
{
    if (m_ptr) m_refs->decWeak(this);
}

void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->removeWeakRef(id);
    //执行原子操作减少impl->mWeak的值
    const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
    LOG_ALWAYS_FATAL_IF(BAD_WEAK(c), "decWeak called on %p too many times",
            this);
    //如果c != 1代表当前对象还在被引用中
    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) {
        //如果是强指针引用对象
        // This is the regular lifetime case. The object is destroyed
        // when the last strong reference goes away. Since weakref_impl
        // outlives the object, it is not destroyed in the dtor, and
        // we'll have to do it here.
        if (impl->mStrong.load(std::memory_order_relaxed)
                == INITIAL_STRONG_VALUE) {
            //强引用控制,但是实际对象构造出来,没有被强引用引用过

            // Decrementing a weak count to zero when object never had a strong
            // reference.  We assume it acquired a weak reference early, e.g.
            // in the constructor, and will eventually be properly destroyed,
            // usually via incrementing and decrementing the strong count.
            // Thus we no longer do anything here.  We log this case, since it
            // seems to be extremely rare, and should not normally occur. We
            // used to deallocate mBase here, so this may now indicate a leak.
            //这是一种异常情况,一般不会存在强引用没有,弱引用还存在
            ALOGW("RefBase: Object at %p lost last weak reference "
                    "before it had a strong reference", impl->mBase);
        } else {
            //case2 至少存在一个强引用情况下可以理解为最后一次强引用下
            //释放引用计数器对象
            // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
            delete impl;
        }
    } else {
        // This is the OBJECT_LIFETIME_WEAK case. The last weak-reference
        // is gone, we can destroy the object.
        //弱引用控制 执行onLastWeakRef回调
        impl->mBase->onLastWeakRef(id);
        //释放实际对象
        delete impl->mBase;
    }
}

通过原子操作减少引用计数,根据旧值确认是否为最后一次弱引用,跟据flag确认当前是强引用控制,还是弱引用控制,这里是弱引用
所以执行impl->mBase->onLastWeakRef(id)回调函数,释放实际对象。
接下来调用父类的析构函数

RefBase::~RefBase()
    int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
    // Life-time of this object is extended to WEAK, in
    // which case weakref_impl doesn't out-live the object and we
    // can free it now.
    if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
        //flag为弱指针控制
        // It's possible that the weak count is not 0 if the object
        // re-acquired a weak reference in its destructor
        //读取mWeak的值为0,表示没有任何弱引用指向对象,那么它会删除 mRefs 对象,即释放引用计数器对象的内存
        if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
            delete mRefs;
        }
    } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
        // We never acquired a strong reference on this object.
        //flag为强指针控制 但是没有强引用引用过的异常情况,打印log
        // TODO: make this fatal, but too much code in Android manages RefBase with
        // new/delete manually (or using other mechanisms such as std::make_unique).
        // However, this is dangerous because it's also common for code to use the
        // sp<T>(T*) constructor, assuming that if the object is around, it is already
        // owned by an sp<>.
        ALOGW("RefBase: Explicit destruction, weak count = %d (in %p). Use sp<> to manage this "
              "object.",
              mRefs->mWeak.load(), this);

#if CALLSTACK_ENABLED
        CallStack::logStack(LOG_TAG);
#endif
    }
    // For debugging purposes, clear mRefs.  Ineffective against outstanding wp's.
    //设置mRefs为空指针 防止野指针出现
    const_cast<weakref_impl*&>(mRefs) = nullptr;
}

获取flag确认是弱引用控制,获取引用计数mWeak的值为0,释放引用计数器对象

5 轻量级指针原理

轻量级指针通过计数器的方式来动态管理对象的释放

5.1 轻量级指针代码
template <class T>
class LightRefBase
{
public:
    inline LightRefBase() : mCount(0) { }
    inline void incStrong(const void* id) const {
        android_atomic_inc(&mCount);
    }
    inline void decStrong(const void* id) const {
        if (android_atomic_dec(&mCount) == 1) {
            delete static_cast<const T*>(this);
        }
    }
    //! DEBUGGING ONLY: Get current strong ref count.
    inline int32_t getStrongCount() const {
        return mCount;
    }

    typedef LightRefBase<T> basetype;

protected:
    inline ~LightRefBase() { }

private:
    friend class ReferenceMover;
    inline static void moveReferences(void* d, void const* s, size_t n,
            const ReferenceConverterBase& caster) { }

private:
    mutable volatile int32_t mCount;
};

可以看到在轻量级指针通过mCount属性来进行计数的,通过IncStrong函数/decStrong函数来进行计数管理,在旧值为1,最后一次引用的情况会去delete目标对象

5.2 轻量级指针例子
#include <utils/LifeRefBase.h>
#include <utils/RefBase.h>

using namespace android;

class MyObject : public LifeRefBase<MyObject> {
public:
    MyObject() {}
    virtual ~MyObject() {}
};

int main() {
    // 创建一个 MyObject 对象的智能指针
    sp<MyObject> object = MyObject::make();
    return 0;
}

可以看到我们创建MyObject对象继承LightRefBase,通过构建/析构目标类型的sp对象在适当时候执行LightRefBase中的incStrong/decStrong来调整引用计数值从而动态释放目标对象

5.3LightRefBase的痛点

LightRefBase的痛点在于无法处理循环引用问题
举例

#include <iostream>
#include <memory>

class B;  // 前向声明

class A {
public:
    std::shared_ptr<B> bPtr;

    A() {
        std::cout << "A Constructor" << std::endl;
    }

    ~A() {
        std::cout << "A Destructor" << std::endl;
    }
};

class B {
public:
    std::shared_ptr<A> aPtr;

    B() {
        std::cout << "B Constructor" << std::endl;
    }

    ~B() {
        std::cout << "B Destructor" << std::endl;
    }
};

int main() {
    std::shared_ptr<A> a = std::make_shared<A>();
    std::shared_ptr<B> b = std::make_shared<B>();

    a->bPtr = b;  // A 持有 B 的智能指针
    b->aPtr = a;  // B 持有 A 的智能指针

    return 0;
}

可以看到我们定义了A,B俩个类,A类中存在spbPtr,B类中存在spaPtr,在我们构建A,B俩个对象后,需要为bPtr和aPtr进行赋值。这时就存在了相互循环引用的情况,系统一次只能delete一个对象,如果出现循环引用那就没办法delete对象

5.4 循环引用的解决方法

上述讲解的sp,wp来解决循环引用
举例子

class A {
public:
    std::shared_ptr<B> bPtr;

    A() {
        std::cout << "A Constructor" << std::endl;
    }

    ~A() {
        std::cout << "A Destructor" << std::endl;
    }
};

class B {
public:
    std::weak_ptr<A> aPtr;

    B() {
        std::cout << "B Constructor" << std::endl;
    }

    ~B() {
        std::cout << "B Destructor" << std::endl;
    }
};

int main() {
    std::shared_ptr<A> a = std::make_shared<A>();
    std::shared_ptr<B> b = std::make_shared<B>();

    a->bPtr = b;
    b->aPtr = a;

    return 0;
}

在这里针对AB类的循环引用,将其中一个类的属性设置为wp类型,就可以解决上述循环引用问题,弱引用计数是不会影响强引用对象的释放,同时弱引用对象也不会导致强引用计数增加,这样在对象所在作用域执行完成后,正常执行sp对象析构操作,来释放实际对象

6 弱指针升级强指针
template<typename T>
sp<T> wp<T>::promote() const
{
    sp<T> result;
    //mptr不为空并且attemptIncStrong成功
    if (m_ptr && m_refs->attemptIncStrong(&result)) {
        //设置sp对象指向的目标对象
        result.set_pointer(m_ptr);
    }
    return result;
}

bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    //增加弱引用计数
    incWeak(id);

    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    //获取当前强引用计数
    int32_t curCount = impl->mStrong.load(std::memory_order_relaxed);

    ALOG_ASSERT(curCount >= 0,
            "attemptIncStrong called on %p after underflow", this);
    //当前对象存在强引用,强引用计数+1
    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
        // we're in the easy/common case of promoting a weak-reference
        // from an existing strong reference.
        //compare_exchange_weak 函数会将 impl->mStrong 的值与 curCount 进行比较
        //,如果相等,则将 curCount+1 存储到 impl->mStrong 中,并返回 true;
        //否则,将 impl->mStrong 的当前值存储到 curCount 中,并返回 false。
        if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                std::memory_order_relaxed)) {
            break;
        }
        // the strong count has changed on us, we need to re-assert our
        // situation. curCount was updated by compare_exchange_weak.
    }
    //当前对象没有被强引用或者最后一个强引用被释放
    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
        // we're now in the harder case of either:
        // - there never was a strong reference on us
        // - or, all strong references have been released
        int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            //强引用控制
            // this object has a "normal" life-time, i.e.: it gets destroyed
            // when the last strong reference goes away
            if (curCount <= 0) {
                //最后一个强引用被删除,释放目标对象 那就减少弱引用计数
                // the last strong-reference got released, the object cannot
                // be revived.
                decWeak(id);
                return false;
            }

            // here, curCount == INITIAL_STRONG_VALUE, which means
            // there never was a strong-reference, so we can try to
            // promote this object; we need to do that atomically.
            while (curCount > 0) {
                //增加强引用计数
                if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                        std::memory_order_relaxed)) {
                    break;
                }
                // the strong count has changed on us, we need to re-assert our
                // situation (e.g.: another thread has inc/decStrong'ed us)
                // curCount has been updated.
            }

            if (curCount <= 0) {
                // promote() failed, some other thread destroyed us in the
                // meantime (i.e.: strong count reached zero).
                //最后一个强引用被删除,释放目标对象 那就减少弱引用计数
                decWeak(id);
                return false;
            }
        } else {
            //弱引用控制
            // this object has an "extended" life-time, i.e.: it can be
            // revived from a weak-reference only.
            // Ask the object's implementation if it agrees to be revived
            if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
                //onIncStrongAttempted回调是否同意被恢复,
                // it didn't so give-up.
                //不同意 减少弱引用计数
                decWeak(id);
                return false;
            }
            // grab a strong-reference, which is always safe due to the
            // extended life-time.
            //增加强引用计数
            curCount = impl->mStrong.fetch_add(1, std::memory_order_relaxed);
            // If the strong reference count has already been incremented by
            // someone else, the implementor of onIncStrongAttempted() is holding
            // an unneeded reference.  So call onLastStrongRef() here to remove it.
            // (No, this is not pretty.)  Note that we MUST NOT do this if we
            // are in fact acquiring the first reference.
            if (curCount != 0 && curCount != INITIAL_STRONG_VALUE) {
                //执行onLastStrongRef回调
                impl->mBase->onLastStrongRef(id);
            }
        }
    }

    impl->addStrongRef(id);

#if PRINT_REFS
    ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
#endif

    // curCount is the value of mStrong before we incremented it.
    // Now we need to fix-up the count if it was INITIAL_STRONG_VALUE.
    // This must be done safely, i.e.: handle the case where several threads
    // were here in attemptIncStrong().
    // curCount > INITIAL_STRONG_VALUE is OK, and can happen if we're doing
    // this in the middle of another incStrong.  The subtraction is handled
    // by the thread that started with INITIAL_STRONG_VALUE.
    if (curCount == INITIAL_STRONG_VALUE) {
        //当前对象未被强引用
        //在调用 decStrong 函数时,如果对象的强引用计数为 INITIAL_STRONG_VALUE,
        //则表示当前并没有任何强引用指向该对象,因此需要将强引用计数设置为 0
        impl->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
                std::memory_order_relaxed);
    }

    return true;
}

弱指针的最大特点是它不能直接操作目标对象,这是怎么样做到的呢?秘密就在于弱指针类没有重载*和->操作符号,而强指针重载了这两个操作符号。但是,如果我们要操作目标对象,应该怎么办呢,这就要把弱指针升级为强指针了
通过promote方法将弱指针升级为强指针
原理构建sp对象,执行attemptIncStrong尝试增加目标对象的弱引用计数,强引用计数,成功的话,设置sp对象内指针指向目标对象
这样promote方法返回的就是新引用目标对象的sp对象,就可以指向目标对象的方法

7 总结

  1. Android中LightRefBase实现了基本的智能指针功能。

  2. 强指针和弱指针是为了解决循环引用中类死锁问题引起的内存泄露。

  3. 引用对象继承RefBase,则拥有了强引用计数和弱引用计数的属性。

  4. 通过extendObjectLifetime函数改变mFlags的值,确定对象受哪种引用计数影响。

  5. 调用incStrong增加强引用计数时,会同时增加强引用计数和弱引用计数,第一次增加强引用计数时,强引用计数从INITIAL_STRONG_VALUE改变为1。

  6. 调用incWeak增加弱引用计数时,只有弱引用计数增加,强引用计数不变。

  7. 弱引用计数≥强引用计数,强增弱必增,弱增强不一定增。

  8. 调用decStrong减少强引用指针时:

    如果对象受强引用计数影响,强引用计数减1,如果此时强引用计数为0,不管弱引用计数是否为0,删除引用对象(此时由于弱引用计数还没减少,所以析构函数不会删除指针对象)。然后弱引用计数减1,如果此时弱引用计数也为0,则删除指针对象。

    如果对象受弱引用计数影响,强引用计数减1,弱引用计数减1,如果此时弱引用计数为0,则删除引用对象,在引用对象的析构函数中会删除指针对象。

  9. 调用decWeak减少弱引用指针时:

    如果对象受强引用计数影响,弱引用计数减1,如果此时弱引用计数为0,看看强引用计数,如果为INITIAL_STRONG_VALUE则说明没有强指针指向该对象,此时直接删除引用对象,指针对象也会随之删除。如果强引用计数不为INITIAL_STRONG_VALUE,则一定为0,因为强引用计数小于等于弱引用计数,此时只需要删除指针对象,因为强引用计数为0并且对象受强引用计数影响,所以对象已经被删除。

    如果对象受弱引用计数影响,弱引用计数减1,如果此时弱引用计数为0,则删除引用对象,指针对象也随之删除。

  10. 强指针和弱指针是两个不同的类,引用对象时会以不同的方式改变强引用计数和弱引用计数的值。

  11. 强指针直接调用incStrong和decStrong,会同时增加或减少强引用计数和弱引用计数。弱指针调用createWeak进而调用incWeak,或者调用decWeak,只影响弱引用计数,不影响强引用计数。

  12. 弱指针不能直接操作目标对象,因为弱指针类没有重载*和->操作符号,而强指针重载了这两个操作符号。如果我们要操作目标对象,就要使用promote函数把弱指针升级为强指针。

  13. 弱指针转化为强指针不一定成功,如果可以转化则使用弱指针的m_ptr构造强指针

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
img
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)

PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题
图片

  • 17
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值