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也是永远都会成功的

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

[cpp]  view plain copy
  1. //增加强引用计数  
  2.   
  3. void RefBase::incStrong(const void* id) const  
  4.   
  5. {  
  6.   
  7. weakref_impl* const refs = mRefs;  
  8.   
  9. //store the object which makes strong reference up, just for track & debug, it is an empty //function  
  10.   
  11. refs->addWeakRef(id);  
  12.   
  13. //increment weak reference  
  14.   
  15.     refs->incWeak(id);  
  16.   
  17. //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.  
  18.   
  19.     refs->addStrongRef(id);  
  20.   
  21.     const int32_t c = android_atomic_inc(&refs->mStrong);  
  22.   
  23.     LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);  
  24.   
  25. #if PRINT_REFS  
  26.   
  27.     LOGD("incStrong of %p from %p: cnt=%d\n"this, id, c);  
  28.   
  29. #endif  
  30.   
  31.     if (c != INITIAL_STRONG_VALUE)  {  
  32.   
  33.         return;  
  34.   
  35. }  
  36.   
  37.    
  38.   
  39. //if the previous value of mStrong equals INITIAL_STRONG_VALUE  
  40.   
  41. //first for increment strong reference  
  42.   
  43. android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);  
  44.   
  45. //notify first reference done  
  46.   
  47.     const_cast<RefBase*>(this)->onFirstRef();  
  48.   
  49. }  
  50.   
  51.    
  52.   
  53. //增加弱引用计数  
  54.   
  55. void RefBase::weakref_type::incWeak(const void* id)  
  56.   
  57. {  
  58.   
  59. weakref_impl* const impl = static_cast<weakref_impl*>(this);  
  60.   
  61. //如上面所写,保存id只为做debug用  
  62.   
  63.     impl->addWeakRef(id);  
  64.   
  65.     const int32_t c = android_atomic_inc(&impl->mWeak);  
  66.   
  67.     LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref"this);  
  68.   
  69. }  
  70.   
  71.    
  72.   
  73. 接下是两个减少引用计数的函数,因为这两个函数涉及到对象的销毁,所以讲的详细点  
  74.   
  75. //减少强引用计数  
  76.   
  77. void RefBase::decStrong(const void* id) const  
  78.   
  79. {  
  80.   
  81.     weakref_impl* const refs = mRefs;  
  82.   
  83.     refs->removeStrongRef(id);  
  84.   
  85.     const int32_t c = android_atomic_dec(&refs->mStrong);  
  86.   
  87. #if PRINT_REFS  
  88.   
  89.     LOGD("decStrong of %p from %p: cnt=%d\n"this, id, c);  
  90.   
  91. #endif  
  92.   
  93. LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);  
  94.   
  95. //强引用减完后为零,尝试销毁对象  
  96.   
  97.     if (c == 1) {  
  98.   
  99.         const_cast<RefBase*>(this)->onLastStrongRef(id);  
  100.   
  101.         //如果未标明OBJECT_LIFETIME_WEAK,也就是默认的life time,销毁对象  
  102.   
  103.         if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {  
  104.   
  105.             delete this;  
  106.   
  107.         }  
  108.   
  109.     }  
  110.   
  111.     refs->removeWeakRef(id);  
  112.   
  113.     refs->decWeak(id);  
  114.   
  115. }  
  116.   
  117.    
  118.   
  119. //减少弱引用计数  
  120.   
  121. void RefBase::weakref_type::decWeak(const void* id)  
  122.   
  123. {  
  124.   
  125.     weakref_impl* const impl = static_cast<weakref_impl*>(this);  
  126.   
  127.     impl->removeWeakRef(id);  
  128.   
  129.     const int32_t c = android_atomic_dec(&impl->mWeak);  
  130.   
  131.     LOG_ASSERT(c >= 1, "decWeak called on %p too many times"this);  
  132.   
  133.     if (c != 1) return;  
  134.   
  135.     //c == 1,弱引用为0,开尝试释放对象  
  136.   
  137. if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {  
  138.   
  139.     //默认life time ,并且对象强引用计数为默认初始值(无强引用计数),释放对象  
  140.   
  141.         if (impl->mStrong == INITIAL_STRONG_VALUE)  
  142.   
  143.             delete impl->mBase;  
  144.   
  145.         else {  
  146.   
  147. //LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase) ;  
  148.   
  149.     //反之释放内部引用管理类  
  150.   
  151.             delete impl;  
  152.   
  153.         }  
  154.   
  155. else {  
  156.   
  157.   //OBJECT_LIFETIME_WEAK,并且life time不包含OBJECT_LIFETIME_FOREVER,释放对象  
  158.   
  159.         impl->mBase->onLastWeakRef(id);  
  160.   
  161.         if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {  
  162.   
  163.             delete impl->mBase;  
  164.   
  165.         }  
  166.   
  167.     }  
  168.   
  169. }  


 

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

[cpp]  view plain copy
  1. RefBase::~RefBase()  
  2.   
  3. {  
  4.   
  5.     if (mRefs->mWeak == 0) {  
  6.   
  7.         delete mRefs;  
  8.   
  9.     }  
  10.   
  11. }  


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

 

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

[cpp]  view plain copy
  1. if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {  
  2.   
  3.      delete this;  
  4.   
  5. }  


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做了哪些操作:

[cpp]  view plain copy
  1. template<typename T>  
  2.   
  3. sp<T> wp<T>::promote() const  
  4.   
  5. {  
  6.   
  7.     //使用wp内的raw pointer和引用管理类来创建sp  
  8.   
  9.     return sp<T>(m_ptr, m_refs);  
  10.   
  11. }  
  12.   
  13.    
  14.   
  15. template<typename T>  
  16.   
  17. sp<T>::sp(T* p, weakref_type* refs)  
  18.   
  19.     : m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)  
  20.   
  21. {  
  22.   
  23. }  


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

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

[cpp]  view plain copy
  1. bool RefBase::weakref_type::attemptIncStrong(const void* id)  
  2.   
  3. {  
  4.   
  5.     incWeak(id);  
  6.   
  7.     weakref_impl* const impl = static_cast<weakref_impl*>(this);  
  8.   
  9.      
  10.   
  11.     int32_t curCount = impl->mStrong;  
  12.   
  13.     LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",  
  14.   
  15.                this);  
  16.   
  17.     //如果强引用计数不为初始值并且大于0,说明对象还活着,赶紧将引用计数+1  
  18.   
  19.     while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {  
  20.   
  21.         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {  
  22.   
  23.             break;  
  24.   
  25.         }  
  26.   
  27.         curCount = impl->mStrong;  
  28.   
  29.     }  
  30.   
  31. //如果强引用计数<=0或者初始值,就代表对象已经被释放了吗?  
  32. <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>  

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

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

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

            2:生命期为OBJECT_LIFETIME_WEAK时,这时就要看onIncStrongAttempted的结果了,默认该函数返回都为true,也就是说,程序的默认行为,allow都为true;

当然你也可以在自己的类中

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

[cpp]  view plain copy
  1.             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK  
  2.   
  3.                   || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);  
  4.   
  5.         } else {  
  6.   
  7.             // Attempting to revive the object...  this is allowed  
  8.   
  9.             // if the object DOES have a longer lifetime (so we can safely  
  10.   
  11.             // call the object with only a weak ref) and the implementation  
  12.   
  13.             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK  
  14.   
  15.                   && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);  
  16.   
  17.         }  
  18.   
  19.         //不允许, promote失败  
  20.   
  21.         if (!allow) {  
  22.   
  23.             decWeak(id);  
  24.   
  25.             return false;  
  26.   
  27.         }  
  28.   
  29.         curCount = android_atomic_inc(&impl->mStrong);  
  30.   
  31.    
  32.   
  33.         // If the strong reference count has already been incremented by  
  34.   
  35.         // someone else, the implementor of onIncStrongAttempted() is holding  
  36.   
  37.         // an unneeded reference.  So call onLastStrongRef() here to remove it.  
  38.   
  39.         // (No, this is not pretty.)  Note that we MUST NOT do this if we  
  40.   
  41.         // are in fact acquiring the first reference.  
  42. if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {  
  43.   
  44.             impl->mBase->onLastStrongRef(id);  
  45.   
  46.         }  
  47.   
  48.     }  
  49.   
  50.      
  51.   
  52.     impl->addWeakRef(id);  
  53.   
  54.     impl->addStrongRef(id);  
  55.   
  56.    
  57.   
  58. #if PRINT_REFS  
  59.   
  60.     LOGD("attemptIncStrong of %p from %p: cnt=%d\n"this, id, curCount);  
  61.   
  62. #endif  
  63.   
  64.    
  65.   
  66.     if (curCount == INITIAL_STRONG_VALUE) {  
  67.   
  68.         android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);  
  69.   
  70.         impl->mBase->onFirstRef();  
  71.   
  72.     }  
  73.   
  74.     return true;  
  75.   
  76. }  

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

1.4  用法

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

[cpp]  view plain copy
  1. class A : public RefBase{  
  2.   
  3. //…  
  4.   
  5. }  
  6.   
  7.    
  8.   
  9. sp<A> sp_inst(new A());  
  10.   
  11. wp<A> wp_weak(sp_inst);  
  12.   
  13.    
  14.   
  15. 然后wp在使用前,需要  
  16.   
  17. sp<A> sp_promote = wp.promote();  
  18.   
  19. //promote 失败  
  20.   
  21. If (sp_promote == NULL)  
  22.   
  23. {  
  24.   
  25. //重新创建对象  
  26.   
  27. sp<A> sp_new(new A());  
  28.   
  29. sp_promote = sp_new;  
  30.   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值