Android C++层的内存回收机制

fmms 12年前
     <h2>1<span style="font-size:16px;">关于C++ Layer的内存回收机制</span></h2>    <p>Android C++层的内存收回主要是通过三个类来实现,分别是RefBase,sp,wp;</p>    <p>SP和WP是两个智能指针模板类,sp是strong pointer,wp则是weak pointer,亦我们常说的强引用和弱引用;实例化sp和wp这两个模板类的类型必须是派生自RefBase的类</p>    <h3>1.1  RefBase类</h3>    <p>因为这个类拥有对内存回收机制的默认实现,所以android上想要支持内存回收机制的类必须派生自RefBase</p>    <p><img alt="Android C++层的内存回收机制 " src="https://simg.open-open.com/show/150748150c2a03d9d4a6b53ece9049b8.bmp" width="371" height="253" /></p>    <p>下面简单介绍下成员变量和成员函数:</p>    <p>mRefs: </p>    <p>weakref_impl对象,派生于RefBase::weakref_type, 包含了对strong ref和weak ref的具体实现,也就是说RefBase中只包含了一些对外的标准操作,具体的实现在weakref_impl内</p>    <p>void incStrong(const void *id):</p>    <p>强引用计数加1,参数id主要用在debug时跟踪调试,一般都为sp或者wp的对象指针</p>    <p>void decStrong(const void *id):</p>    <p>强引用计数减1,参数id含义同上</p>    <p>void forceIncStrong(const void *id):</p>    <p>强制引用计数加1</p>    <p>Int32_t getStrongCount():</p>    <p>获去强引用计数值</p>    <p>weakref_type * createWeak(const void *id)</p>    <p>弱引用计数加1,然后返回weakref_impl对象</p>    <p>weakref_type* getWeakRefs()</p>    <p>获取weakref_impl对象</p>    <p>void extendObjectLifetime(int32_t mode):</p>    <p>扩展对象的生命期,默认为0,可设置为</p>    <p>OBJECT_LIFETIME_WEAK   = 0x0001,</p>    <p>OBJECT_LIFETIME_FOREVER = 0x0003</p>    <p>这几个参数的作用在下面会详细描述</p>    <p>virtual void onFirstRef()</p>    <p>虚函数,在第一次新增引用计数时,会调用此函数,接下去的其他函数都类似</p>    <p> </p>    <p>上面也有提到了,RefBase有一个内部基类weakref_type,</p>    <p><img alt="Android C++层的内存回收机制 " src="https://simg.open-open.com/show/f52566a46bf563574cfe8953ca9e93b5.bmp" width="225" height="120" /></p>    <p>它主要包含了对弱引用计数的基本操作,</p>    <p>void incWeak(const void*id):</p>    <p>弱引用计数加1,id参数的意义同上</p>    <p>void decWeak(const void *id):</p>    <p>弱引用计数减1,id同上</p>    <p>bool attemptIncStrong(const void *id):</p>    <p>尝试增加强引用计数,这个函数会在wp promote获取sp时被调用,主要确认wp promote为sp是否成功</p>    <p>bool attemptIncWeak(const void *id):</p>    <p>尝试增加弱引用计数,这个功能只在object lifetime设置为OBJECT_LIFETIME_FOREVER有效</p>    <p>Int32_t getWeakCount():</p>    <p>获取弱引用计数值</p>    <p> </p>    <p>在RefBase中,可以通过extendObjectLifetime来设置lifetime,有三种life time:</p>    <p>1:default(0),强引用和弱引用的默认行为,不管弱应用计数的值为多少,只要强引用计数的值为0,就释放对象</p>    <p>2:OBJECT_LIFETIME_WEAK,在这种状态下,如果强引用为0时,对象不会被释放,只有在弱引用计数为0的情况下,对象才会被释放</p>    <p>3:OBJECT_LIFETIME_WEAK | OBJECT_LIFETIME_FOREVER,在这种状态下,对象永不会释放</p>    <p> </p>    <p>第三种情况比较猛,设置了,除非主动delete raw pointer,否则在sp和wp的规则下,是不会被释放的,当然,promote也是永远都会成功的</p>    <p> </p>    <p>在增加或者减少强引用计数的同时,弱引用计数也会被增加或减少,它们总是配对出现的,下面简单看下几个关键部分的代码:</p>    <p>//增加强引用计数</p>    <p></p>    <pre class="brush:cpp; toolbar: true; auto-links: false;">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();  }</pre>    <p></p>    <p> </p>    <p>//增加弱引用计数</p>    <p></p>    <pre class="brush:cpp; toolbar: true; auto-links: false;">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);  }</pre>    <p></p>    <p> </p>    <p>接下是两个减少引用计数的函数,因为这两个函数涉及到对象的销毁,所以讲的详细点</p>    <p>//减少强引用计数</p>    <p></p>    <pre class="brush:cpp; toolbar: true; auto-links: false;">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);  }</pre>    <p></p>    <p> </p>    <p>//减少弱引用计数</p>    <p></p>    <pre class="brush:cpp; toolbar: true; auto-links: false;">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;          }      }  }</pre>    <p></p>    <p> </p>    <p>如果对上面一会释放imple->mBase,一会释放weakref_impl有疑问,继续看RefBase的析构函数:</p>    <p></p>    <pre class="brush:cpp; toolbar: true; auto-links: false;">RefBase::~RefBase()  {      if (mRefs->mWeak == 0) {          delete mRefs;      }  }</pre>    <p></p>    <p>RefBase被销毁时,只有当弱引用计数为0时,才会释放weakref_imp对象,上面decWeak中第一和第三个delete,直接释放impl->mBase,肯定没问题,因为这时候弱引用计数已经为0,weakref_imp对象在析构中正常被释放</p>    <p> </p>    <p>再看第二个delete,在默认life time下,如果RefBase通过sp建立了强引用,在强引用为0的情况下在执行RefBase::decStrong中的以下代码,</p>    <p>if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {</p>    <p>     delete this;</p>    <p>}</p>    <p>RefBase对象肯定会被释放,在释放时调用析构时,由于mRefs->mWeak == 0不成立,内部weaktype_imp对象不会被释放,所以这里需要delete impl以释放内部引用管理对象</p>    <h3>1.2  创建sp和wp对象</h3>    <p>创建sp:</p>    <p>    sp(T* other):直接使用Raw pointer来创建sp对象</p>    <p>sp(const sp<T>& other):从已有的sp对象拷贝构造</p>    <p>创建wp:</p>    <p>    wp(T* other):直接使用raw pointer来创建wp对象</p>    <p>    wp(const wp<T>& other):从已有的wp对象拷贝</p>    <p>wp(const sp<T>& other):从已有的sp对象拷贝</p>    <h3>1.3  关于promote</h3>    <p>如果想通过已有的wp对象获取对应的内建对象,需要调用promote来尝试提升为sp,然后通过sp来判断promote是否成功,如果成功,说明内建对象还存在,可以继续使用,反之,需要创建新的内建对象</p>    <p> </p>    <p>下面来详细查看下promote做了哪些操作:</p>    <p></p>    <pre class="brush:cpp; toolbar: true; auto-links: false;">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)  {  }</pre>    <p></p>    <p>调用引用管理类的函数attemptIncStrong来尝试增加强引用计数,如成功,说明raw pointer保存的对象还未被释放,可以继续使用,反之,返回false,promote失败</p>    <p>接下去详细看下attemptIncStrong的实现:</p>    <p>bool RefBase::weakref_type::attemptIncStrong(const void* id)</p>    <p>{</p>    <p>    incWeak(id);</p>    <p>    weakref_impl* const impl = static_cast<weakref_impl*>(this);</p>    <p>    </p>    <p>    int32_t curCount = impl->mStrong;</p>    <p>    LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",</p>    <p>               this);</p>    <p>    //如果强引用计数不为初始值并且大于0,说明对象还活着,赶紧将引用计数+1</p>    <p>    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {</p>    <p>        if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {</p>    <p>            break;</p>    <p>        }</p>    <p>        curCount = impl->mStrong;</p>    <p>    }</p>    <p>//如果强引用计数<=0或者初始值,就代表对象已经被释放了吗?</p>    <p>//不一定</p>    <p>    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {</p>    <p>        bool allow;</p>    <p>        if (curCount == INITIAL_STRONG_VALUE) {</p>    <p>            // attempting to acquire first strong reference...  this is allowed</p>    <p>            // if the object does NOT have a longer lifetime (meaning the</p>    <p>            // implementation doesn't need to see this), or if the implementation</p>    <p>            // allows it to happen.</p>    <p>            /*curCount为初始值,说明sp未被创建,从一开始都是wp独自掌管,这种情况下,对象肯定存在,剩下就是根据程序需要,让不让它promote成功</p>    <p>            根据以下代码,有两种情况:</p>    <p>            1:生命期不为OBJECT_LIFETIME_WEAK,这时第一判断为true,onIncStrongAttempted结果忽略,allow为true</p>    <p>            2:生命期为OBJECT_LIFETIME_WEAK时,这时就要看onIncStrongAttempted的结果了,默认该函数返回都为true,也就是说,程序的默认行为,allow都为true;当然你也可以在自己的类中</p>    <p>根据需要修改onIncStrongAttempted的默认行为来控制是否允许在这种情况下让其promote成功*/</p>    <p>            allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK</p>    <p>                  || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);</p>    <p>        } else {</p>    <p>            // Attempting to revive the object...  this is allowed</p>    <p>            // if the object DOES have a longer lifetime (so we can safely</p>    <p>            // call the object with only a weak ref) and the implementation</p>    <p>            allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK</p>    <p>                  && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);</p>    <p>        }</p>    <p>        //不允许, promote失败</p>    <p>        if (!allow) {</p>    <p>            decWeak(id);</p>    <p>            return false;</p>    <p>        }</p>    <p>        curCount = android_atomic_inc(&impl->mStrong);</p>    <p> </p>    <p>        // If the strong reference count has already been incremented by</p>    <p>        // someone else, the implementor of onIncStrongAttempted() is holding</p>    <p>        // an unneeded reference.  So call onLastStrongRef() here to remove it.</p>    <p>        // (No, this is not pretty.)  Note that we MUST NOT do this if we</p>    <p>        // are in fact acquiring the first reference.</p>    <p>        if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {</p>    <p>            impl->mBase->onLastStrongRef(id);</p>    <p>        }</p>    <p>    }</p>    <p>    </p>    <p>    impl->addWeakRef(id);</p>    <p>    impl->addStrongRef(id);</p>    <p> </p>    <p>#if PRINT_REFS</p>    <p>    LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);</p>    <p>#endif</p>    <p> </p>    <p>    if (curCount == INITIAL_STRONG_VALUE) {</p>    <p>        android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);</p>    <p>        impl->mBase->onFirstRef();</p>    <p>    }</p>    <p>    </p>    <p>    return true;</p>    <p>}</p>    <p> </p>    <p>attemptIncStrong成功,promote成功,继续使用已有的Refbase对象实例,如果失败了,则需重新创建新的对象。</p>    <p> </p>    <h3>1.4  用处</h3>    <p>在android中,在实现基于RefBase的类中,大部分都使用默认的生命期,只有BpBinder会调用 extendObjectLifetime(OBJECT_LIFETIME_WEAK)来更改默认生命期;针对默认生命期,其用处和java的强引用和 弱引用类似。</p>    <p> </p> 转自:    <a href="/misc/goto?guid=4959500609112871211" target="_blank">http://blog.csdn.net/zhejiang9/article/details/7193457</a>