zoukankan      html  css  js  c++  java
  • Android C++回收机制(转)

     

    1关于C++ Layer的内存回收机制

    Android C++层的内存收回主要是通过三个类来实现,分别是RefBase,sp,wp;

    SP和WP是两个智能指针模板类,sp是strong pointer,wp则是weak pointer,亦我们常说的强引用和弱引用;实例化sp和wp这两个模板类的类型必须是派生自RefBase的类
    1.1  RefBase类

    因为这个类拥有对内存回收机制的默认实现,所以android上想要支持内存回收机制的类必须派生自RefBase

    下面简单介绍下成员变量和成员函数:

    mRefs:

    weakref_impl对象,派生于RefBase::weakref_type, 包含了对strong ref和weak ref的具体实现,也就是说RefBase中只包含了一些对外的标准操作,具体的实现在weakref_impl内

    void incStrong(const void *id):

    强引用计数加1,参数id主要用在debug时跟踪调试,一般都为sp或者wp的对象指针

    void decStrong(const void *id):

    强引用计数减1,参数id含义同上

    void forceIncStrong(const void *id):

    强制引用计数加1

    Int32_t getStrongCount():

    获去强引用计数值

    weakref_type * createWeak(const void *id)

    弱引用计数加1,然后返回weakref_impl对象

    weakref_type* getWeakRefs()

    获取weakref_impl对象

    void extendObjectLifetime(int32_t mode):

    扩展对象的生命期,默认为0,可设置为

    OBJECT_LIFETIME_WEAK   = 0x0001,

    OBJECT_LIFETIME_FOREVER = 0x0003

    这几个参数的作用在下面会详细描述

    virtual void onFirstRef()

    虚函数,在第一次新增引用计数时,会调用此函数,接下去的其他函数都类似

    上面也有提到了,RefBase有一个内部基类weakref_type,

    它主要包含了对弱引用计数的基本操作,

    void incWeak(const void*id):

    弱引用计数加1,id参数的意义同上

    void decWeak(const void *id):

    弱引用计数减1,id同上

    bool attemptIncStrong(const void *id):

    尝试增加强引用计数,这个函数会在wp promote获取sp时被调用,主要确认wp promote为sp是否成功

    bool attemptIncWeak(const void *id):

    尝试增加弱引用计数,这个功能只在object lifetime设置为OBJECT_LIFETIME_FOREVER有效

    Int32_t getWeakCount():

    获取弱引用计数值

    在RefBase中,可以通过extendObjectLifetime来设置lifetime,有三种life time:

    1:default(0),强引用和弱引用的默认行为,不管弱应用计数的值为多少,只要强引用计数的值为0,就释放对象

    2:OBJECT_LIFETIME_WEAK,在这种状态下,如果强引用为0时,对象不会被释放,只有在弱引用计数为0的情况下,对象才会被释放

    3:OBJECT_LIFETIME_WEAK | OBJECT_LIFETIME_FOREVER,在这种状态下,对象永不会释放

    第三种情况比较猛,设置了,除非主动delete raw pointer,否则在sp和wp的规则下,是不会被释放的,当然,promote也是永远都会成功的

    在增加或者减少强引用计数的同时,弱引用计数也会被增加或减少,它们总是配对出现的,下面简单看下几个关键部分的代码:

    //增加强引用计数

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

    {

    weakref_impl* const refs = mRefs;

    //store the object which makes strong reference up, just for track & debug, it is an empty //function

    refs->addWeakRef(id);

    //increment weak reference

        refs->incWeak(id);

    //store the object which makes strong reference up, just for track & debug, if not in debug, it //is an empty function, nothing will be done.

        refs->addStrongRef(id);

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

        LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);

    #if PRINT_REFS

        LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);

    #endif

        if (c != INITIAL_STRONG_VALUE)  {

            return;

    }

    //if the previous value of mStrong equals INITIAL_STRONG_VALUE

    //first for increment strong reference

    android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);

    //notify first reference done

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

    }

    //增加弱引用计数

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

    {

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

    //如上面所写,保存id只为做debug用

        impl->addWeakRef(id);

        const int32_t c = android_atomic_inc(&impl->mWeak);

        LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);

    }

    接下是两个减少引用计数的函数,因为这两个函数涉及到对象的销毁,所以讲的详细点

    //减少强引用计数

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

    {

        weakref_impl* const refs = mRefs;

        refs->removeStrongRef(id);

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

    #if PRINT_REFS

        LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);

    #endif

    LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);

    //强引用减完后为零,尝试销毁对象

        if (c == 1) {

            const_cast<RefBase*>(this)->onLastStrongRef(id);

            //如果未标明OBJECT_LIFETIME_WEAK,也就是默认的life time,销毁对象

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

                delete this;

            }

        }

        refs->removeWeakRef(id);

        refs->decWeak(id);

    }

    //减少弱引用计数

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

    {

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

        impl->removeWeakRef(id);

        const int32_t c = android_atomic_dec(&impl->mWeak);

        LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);

        if (c != 1) return;

        //c == 1,弱引用为0,开尝试释放对象

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

        //默认life time ,并且对象强引用计数为默认初始值(无强引用计数),释放对象

            if (impl->mStrong == INITIAL_STRONG_VALUE)

                delete impl->mBase;

            else {

    //LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase) ;

        //反之释放内部引用管理类

                delete impl;

            }

    } else {

      //OBJECT_LIFETIME_WEAK,并且life time不包含OBJECT_LIFETIME_FOREVER,释放对象

            impl->mBase->onLastWeakRef(id);

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

                delete impl->mBase;

            }

        }

    }

    如果对上面一会释放imple->mBase,一会释放weakref_impl有疑问,继续看RefBase的析构函数:

    RefBase::~RefBase()

    {

        if (mRefs->mWeak == 0) {

            delete mRefs;

        }

    }

    RefBase被销毁时,只有当弱引用计数为0时,才会释放weakref_imp对象,上面decWeak中第一和第三个delete,直接释放impl->mBase,肯定没问题,因为这时候弱引用计数已经为0,weakref_imp对象在析构中正常被释放

    再看第二个delete,在默认life time下,如果RefBase通过sp建立了强引用,在强引用为0的情况下在执行RefBase::decStrong中的以下代码,

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

         delete this;

    }

    RefBase对象肯定会被释放,在释放时调用析构时,由于mRefs->mWeak == 0不成立,内部weaktype_imp对象不会被释放,所以这里需要delete impl以释放内部引用管理对象
    1.2  创建sp和wp对象

    创建sp:

        sp(T* other):直接使用Raw pointer来创建sp对象

    sp(const sp<T>& other):从已有的sp对象拷贝构造

    创建wp:

        wp(T* other):直接使用raw pointer来创建wp对象

        wp(const wp<T>& other):从已有的wp对象拷贝

    wp(const sp<T>& other):从已有的sp对象拷贝
    1.3  关于promote

    如果想通过已有的wp对象获取对应的内建对象,需要调用promote来尝试提升为sp,然后通过sp来判断promote是否成功,如果成功,说明内建对象还存在,可以继续使用,反之,需要创建新的内建对象

    下面来详细查看下promote做了哪些操作:

    template<typename T>

    sp<T> wp<T>::promote() const

    {

        //使用wp内的raw pointer和引用管理类来创建sp

        return sp<T>(m_ptr, m_refs);

    }

    template<typename T>

    sp<T>::sp(T* p, weakref_type* refs)

        : m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)

    {

    }

    调用引用管理类的函数attemptIncStrong来尝试增加强引用计数,如成功,说明raw pointer保存的对象还未被释放,可以继续使用,反之,返回false,promote失败

    接下去详细看下attemptIncStrong的实现:

    bool RefBase::weakref_type::attemptIncStrong(const void* id)

    {

        incWeak(id);

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

      

        int32_t curCount = impl->mStrong;

        LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",

                   this);

        //如果强引用计数不为初始值并且大于0,说明对象还活着,赶紧将引用计数+1

        while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {

            if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {

                break;

            }

            curCount = impl->mStrong;

        }

    //如果强引用计数<=0或者初始值,就代表对象已经被释放了吗?

    //不一定

        if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {

            bool allow;

            if (curCount == INITIAL_STRONG_VALUE) {

                // attempting to acquire first strong reference...  this is allowed

                // if the object does NOT have a longer lifetime (meaning the

                // implementation doesn't need to see this), or if the implementation

                // allows it to happen.

                /*curCount为初始值,说明sp未被创建,从一开始都是wp独自掌管,这种情况下,对象肯定存在,剩下就是根据程序需要,让不让它promote成功

                根据以下代码,有两种情况:

                1:生命期不为OBJECT_LIFETIME_WEAK,这时第一判断为true,onIncStrongAttempted结果忽略,allow为true

                2:生命期为OBJECT_LIFETIME_WEAK时,这时就要看onIncStrongAttempted的结果了,默认该函数返回都为true,也就是说,程序的默认行为,allow都为true;当然你也可以在自己的类中

    根据需要修改onIncStrongAttempted的默认行为来控制是否允许在这种情况下让其promote成功*/

                allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK

                      || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);

            } else {

                // Attempting to revive the object...  this is allowed

                // if the object DOES have a longer lifetime (so we can safely

                // call the object with only a weak ref) and the implementation

                allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK

                      && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);

            }

            //不允许, promote失败

            if (!allow) {

                decWeak(id);

                return false;

            }

            curCount = android_atomic_inc(&impl->mStrong);

            // 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) {

                impl->mBase->onLastStrongRef(id);

            }

        }

      

        impl->addWeakRef(id);

        impl->addStrongRef(id);

    #if PRINT_REFS

        LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);

    #endif

        if (curCount == INITIAL_STRONG_VALUE) {

            android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);

            impl->mBase->onFirstRef();

        }

      

        return true;

    }

    attemptIncStrong成功,promote成功,继续使用已有的Refbase对象实例,如果失败了,则需重新创建新的对象。


    1.4  用法

    在android中,在实现基于RefBase的类中,大部分都使用默认的生命期,只有BpBinder会调用extendObjectLifetime(OBJECT_LIFETIME_WEAK)来更改默认生命期;针对默认生命期,其用处和Java的强引用和弱引用类似,下面用代码来粗略的描述下sp和wp的使用:

    class A : public RefBase{

    //…

    }

    sp<A> sp_inst(new A());

    wp<A> wp_weak(sp_inst);

    然后wp在使用前,需要

    sp<A> sp_promote = wp.promote();

    //promote 失败

    If (sp_promote == NULL)

    {

    //重新创建对象

    sp<A> sp_new(new A());

    sp_promote = sp_new;

    }

  • 相关阅读:
    某个牛人做WINDOWS系统文件详解
    常用ASP脚本程序集锦
    LINUX基础:文件安全与权限
    proftpd+mysql+quota
    apache2.0.49tomcat5.0.19jk2建立virtualHost
    URL Redirection(转) Anny
    顶级域名后缀列表(转) Anny
    \u4E00\u9FA5意义 Anny
    How to POST Form Data Using Ruby(转) Anny
    How to get rid of 'Enter password to unlock your login keyring' in Ubuntu(转) Anny
  • 原文地址:https://www.cnblogs.com/kenter/p/2417502.html
Copyright © 2011-2022 走看看