安卓系统智能指针:RefBase、sp、wp

一、C++析构函数的调用

在C++编程中,有两个很让人头痛的问题:一是忘记释放动态申 请的对象从而造成内存泄露(通过new生成的对象,需要调用delete才能释放内存);二是对象在一个地方释放后,又在别的地方被使用,从而引起内存访问错误(多个指针指向同一个对象,其中一个指针delete)。

#include <iostream>
using namespace std;
class A{
public :
    A(){
        cout << "无参构造函数被调用" << endl;
    }
    ~A(){
        cout << "析构函数被调用" << endl;
    }
};
void test1(){
    A testA; //对象建立
    //方法结束时,由系统自动调用析构函数释放对象
}

void test2(){
    A* pa = new A();
    delete pa; //手动调用析构函数释放对象
}

void test3(){
    A* pa = new A();
     //方法结束时,系统不会自动调用析构函数释放对象,对象存在内存中
}

 

二、RefBase与sp、wp

1、RefBase介绍

RefBase是安卓CPP中所有对象的始祖,类似于JAVA中的Object对象。

在安卓中,RefBase结合sp(强指针)和wp(弱指针),实现了通过引用计数的方法来控制对象的生命周期的机制,解决对象的自动释放的问题。在C++编程中,有两个很让人头痛的问题:一是忘记释放动态申 请的对象从而造成内存泄露(通过new生成的对象,需要调用delete才能释放内存);二是对象在一个地方释放后,又在别的地方被使用,从而引起内存访问错误(多个指针指向同一个对象,其中一个指针delete)。在使用RefBase后,动态申请的内存将会被自动释放(有点类似Java的垃圾回收),不需要再使用delete来释放对象,也不需要考虑一个对 象是否已经在其它地方被释放了,从而使程序编写工作减轻不少,而程序的稳定性大大提高。

 

2、RefBase类结构

生成一个RefBase对象,会默认生成一个weakref_impl对,并且用指针mRefs指向此对象,weakref_impl类继承于weakref_type类,而weakref_type是RefBase的内部类,weakref_impl有一个mBase指针指向RefBase对象。关系如下图:

 

三个类的构造函数或定义:

RefBase::RefBase()
    : mRefs(new weakref_impl(this))
{
}
//weakref_impl的定义
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
    std::atomic<int32_t>    mStrong;
    std::atomic<int32_t>    mWeak;
    RefBase* const          mBase;
    std::atomic<int32_t>    mFlags;
//weakref_impl的构造函数
weakref_impl(RefBase* base)
    : mStrong(INITIAL_STRONG_VALUE)
    , mWeak(0)
    , mBase(base)
    , mFlags(0)
    , mStrongRefs(NULL)
    , mWeakRefs(NULL)
    , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
    , mRetain(false)
{
}
class RefBase
{
public:
            void            incStrong(const void* id) const;
            void            decStrong(const void* id) const;

            void            forceIncStrong(const void* id) const;

            //! DEBUGGING ONLY: Get current strong ref count.
            int32_t         getStrongCount() const;
//weakref_type定义
    class weakref_type
    {
    public:
        RefBase*            refBase() const;

        void                incWeak(const void* id);
        void                decWeak(const void* id);

        // acquires a strong reference if there is already one.
        bool                attemptIncStrong(const void* id);

        // acquires a weak reference if there is already one.
        // This is not always safe. see ProcessState.cpp and BpBinder.cpp
        // for proper use.
        bool                attemptIncWeak(const void* id);

        //! DEBUGGING ONLY: Get current weak ref count.
        int32_t             getWeakCount() const;

3、三个重要的变量

weakref_impl中有三个重要的变量:

    std::atomic<int32_t>    mStrong;
    std::atomic<int32_t>    mWeak;
    std::atomic<int32_t>    mFlags;

mStrong为强指针计数、mWeak为弱指针计数、mFlags为控制释放内存的标志。

mFlags的取值有:

enum {
    OBJECT_LIFETIME_STRONG  = 0x0000,
    OBJECT_LIFETIME_WEAK    = 0x0001,
    OBJECT_LIFETIME_MASK    = 0x0001
};

OBJECT_LIFETIME_STRONG :默认值,有申请强指针时,最后一个强指针删除时,对象被清0,没有申请强指针时,最后一个弱指针被删除时清0

OBJECT_LIFETIME_WEAK:最后一个指针被删除时清0

通过extendObjectLifetime 可以修改mFlags,从而修改对象的生命周期。

4、RefBase的使用

(1)先强化再弱化

class A : public RefBase
{
    
}
int main()
{
    A* PA = new A;
    {
        sp<A> spA(pA);
        wp<A> wpA(spA);
        //大括号结束,先析构wp,再析构sp
    }
}

sp<A>强指针作用:A继承RefBase,所以有一个weakref_impl对象,sp<A>使A中weakref_impl对象的mStrong和mWeak各加1.

sp<T> 
    ==> m_ptr -> incStrong ()
        ==> refs->incWeak()
        ==> refs->mStrong.fetch_add(1, std::memory_order_relaxed);
template<typename T>
sp<T>::sp(const sp<T>& other)
        : m_ptr(other.m_ptr) {
    if (m_ptr)
        m_ptr->incStrong(this);
}


 

void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->incWeak(id);

    refs->addStrongRef(id);
    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)  {
        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();
}

wp<A>弱指针作用:wp<A>使A中weakref_impl对象的mWeak加1.

并且通过m_refs保存影子对象和m_ptr保存实际对象

template<typename T>
wp<T>::wp(T* other)
    : m_ptr(other)
{
    if (other) m_refs = other->createWeak(this);
}

 

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

(2)如何自动清除对象

 {
        sp<A> spA(pA);
        wp<A> wpA(spA);
        //大括号结束,先析构wp,再析构sp
    }

上面代码段运行完后,会调用wpA的析构函数,再调spA的析构函数。

函数调用:

//先析构wp,把mWeak减1 
~wp()
    ==>m_refs->decWeak(this)
        ==> impl->mWeak.fetch_sub(1, std::memory_order_release);
//再析构sp
~sp()
    ==>m_ptr->decStrong(this)
        ==>refs->mStrong.fetch_sub(1, std::memory_order_release);
        ==>delete this;//mFlags为STRONG,删除实际对象
        ==>refs->decWeak(id);
            ==>delete impl;//删除影子对象

 

小结:

  • 先sp再wp,sp时,强弱计数各加1,wp时,弱计数加1
  • mFlags为OBJECT_LIFETIME_STRONG 时:
    • 强引用为0将导致实际对象被delete
    • 弱引用为0将导致影子对象被delete

 

(3)也可以先wp再sp

int main()
{
    A* PA = new A;
    wp<A> wpA(PA);
    sp<A> spA = wpA.promote();
}

wp使才对象A中和weakref_impl中的弱引用mWeak加1

wpA.promote()调用流程:

wpA.promote()
    ==> sp<T>(m_ptr,m_refs) ;
        ==>refs->attemptIncStrong(this);
            ==>incWeak(id)
            ==>impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                std::memory_order_relaxed)

wpA.promote()使强弱引用值都加1.

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值