Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析(3)

简介:

 提供引用计数器的类RefBase我们就暂时介绍到这里,后面我们再结合智能指针类一起分析,现在先来看看强指针类和弱指针类的定义。强指针类的定义我们在前面介绍轻量级指针的时候已经见到了,就是sp类了,这里就不再把它的代码列出来了。我们来看看它的构造函数的实现:

 
 
  1. template<typename T>   
  2. sp<T>::sp(T* other)   
  3.     : m_ptr(other)   
  4. {   
  5.     if (other) other->incStrong(this);   
  6. }   

  这里传进来的参数other一定是继承于RefBase类的,因此,在函数的内部,它调用的是RefBase类的incStrong函数,它定义在frameworks/base/libs/utils/RefBase.cpp文件中: 

 
 
  1. void RefBase::incStrong(const void* id) const   
  2. {   
  3.     weakref_impl* const refs = mRefs;   
  4.     refs->addWeakRef(id);   
  5.     refs->incWeak(id);   
  6.     refs->addStrongRef(id);    
  7.    
  8.     const int32_t c = android_atomic_inc(&refs->mStrong);    
  9.     LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);   
  10.    
  11.     #if PRINT_REFS    
  12.     LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);   
  13.     #endif    
  14.    
  15.     if (c != INITIAL_STRONG_VALUE) {    
  16.         return;    
  17.     }    
  18.    
  19.     android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);    
  20.     const_cast<RefBase*>(this)->onFirstRef();   
  21. }   

  成员变量mRefs是在RefBase类的构造函数中创建的:

 
 
  1. RefBase::RefBase()   
  2.     : mRefs(new weakref_impl(this))   
  3. {   
  4. //    LOGV("Creating refs %p with RefBase %p\n", mRefs, this);   
  5. }   

 在这个incStrong函数中,主要做了三件事情:

 一是增加弱引用计数:

 
 
  1. refs->addWeakRef(id);   
  2. refs->incWeak(id);   

 二是增加强引用计数:

 
 
  1. refs->addStrongRef(id);   
  2. const int32_t c = android_atomic_inc(&refs->mStrong);   

   三是如果发现是首次调用这个对象的incStrong函数,就会调用一个这个对象的onFirstRef函数,让对象有机会在对象被首次引用时做一些处理逻辑:

 
 
  1. if (c != INITIAL_STRONG_VALUE)  {   
  2.     return;   
  3. }   
  4.    
  5. android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);   
  6. const_cast<RefBase*>(this)->onFirstRef();   

 这里的c返回的是refs->mStrong加1前的值,如果发现等于INITIAL_STRONG_VALUE,就说明这个对象的强引用计数是第一次被增加,因此,refs->mStrong就是初始化为INITIAL_STRONG_VALUE的,它的值为:#define INITIAL_STRONG_VALUE (1<<28)  
   这个值加1后等于1<<28 + 1,不等于1,因此,后面要再减去-INITIAL_STRONG_VALUE,于是,refs->mStrong就等于1了,就表示当前对象的强引用计数值为1了,这与这个对象是第一次被增加强引用计数值的逻辑是一致的。
        回过头来看弱引用计数是如何增加的,首先是调用weakref_impl类的addWeakRef函数,我们知道,在Release版本中,这个函数也不做,而在Debug版本中,这个函数增加了一个ref_entry对象到了weakref_impl对象的mWeakRefs列表中,表示此weakref_impl对象的弱引用计数被增加了一次。接着又调用了weakref_impl类的incWeak函数,真正增加弱引用计数值就是在这个函数实现的了,weakref_impl类的incWeak函数继承于其父类weakref_type的incWeak函数:

 
 
  1. void RefBase::weakref_type::incWeak(const void* id)   
  2. {   
  3.     weakref_impl* const impl = static_cast<weakref_impl*>(this);   
  4.     impl->addWeakRef(id);   
  5.     const int32_t c = android_atomic_inc(&impl->mWeak);   
  6.     LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);   
  7. }   

  增加弱引用计数是下面语句执行的:const int32_t c = android_atomic_inc(&impl->mWeak);     但是前面为什么又调用了一次addWeakRef函数呢?前面不是已经调用过了吗?在Release版本中,因为weakref_impl类的addWeakRef函数是空实现,这里再调用一次没有什么害处,但是如果在Debug版本,岂不是冗余了吗?搞不清,有人问过负责开发Android系统Binder通信机制模块的作者Dianne Hackborn这个问题,他是这样回答的: 

 http://groups.google.com/group/android-platform/browse_thread/thread/cc641db8487dd83

        Ah I see.  Well the debug code may be broken, though I wouldn't leap to that 
        conclusion without actually testing it; I know it has been used in the 
        past.  Anyway, these things get compiled out in non-debug builds, so there 
        is no reason to change them unless you are actually trying to use this debug 
        code and it isn't working and need to do this to fix it. 

        既然他也不知道怎么回事,我们也不必深究了,知道有这么回事就行。

        这里总结一下强指针类sp在其构造函数里面所做的事情就是分别为目标对象的强引用计数和弱引和计数增加了1。

        再来看看强指针类的析构函数的实现:

 
 
  1. template<typename T>   
  2. sp<T>::~sp()   
  3. {   
  4.     if (m_ptr) m_ptr->decStrong(this);   
  5. }   

     同样,这里的m_ptr指向的目标对象一定是继承了RefBase类的,因此,这里调用的是RefBase类的decStrong函数,这也是定义在frameworks/base/libs/utils/RefBase.cpp文件中:

 
 
  1. void RefBase::decStrong(const void* id) const   
  2. {   
  3.     weakref_impl* const refs = mRefs;   
  4.     refs->removeStrongRef(id);   
  5.     const int32_t c = android_atomic_dec(&refs->mStrong);   
  6. #if PRINT_REFS   
  7.     LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);   
  8. #endif   
  9.     LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);   
  10.     if (c == 1) {   
  11.         const_cast<RefBase*>(this)->onLastStrongRef(id);   
  12.         if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {   
  13.             delete this;   
  14.         }   
  15.     }   
  16.     refs->removeWeakRef(id);   
  17.     refs->decWeak(id);   
  18. }   

  这里的refs->removeStrongRef函数调用语句是对应前面在RefBase::incStrong函数里的refs->addStrongRef函数调用语句的,在Release版本中,这也是一个空实现函数,真正实现强引用计数减1的操作是下面语句:

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

   如果发现减1前,此对象的强引用计数为1,就说明从此以后,就再没有地方引用这个目标对象了,这时候,就要看看是否要delete这个目标对象了:

 
 
  1. if (c == 1) {   
  2.     const_cast<RefBase*>(this)->onLastStrongRef(id);   
  3.     if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {   
  4.         delete this;   
  5.     }   
  6. }   

  在强引用计数为0的情况下,如果对象的标志位OBJECT_LIFETIME_WEAK被设置了,就说明这个对象的生命周期是受弱引用计数所控制的,因此,这时候就不能delete对象,要等到弱引用计数也为0的情况下,才能delete这个对象。

 

        接下来的ref->removeWeakRef函数调用语句是对应前面在RefBase::incStrong函数里的refs->addWeakRef函数调用语句的,在Release版本中,这也是一个空实现函数,真正实现强引用计数减1的操作下面的refs->decWeak函数,weakref_impl类没有实现自己的decWeak函数,它继承了weakref_type类的decWeak函数:

 
 
  1. void RefBase::weakref_type::decWeak(const void* id)   
  2. {   
  3.     weakref_impl* const impl = static_cast<weakref_impl*>(this);   
  4.     impl->removeWeakRef(id);   
  5.     const int32_t c = android_atomic_dec(&impl->mWeak);   
  6.     LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);   
  7.     if (c != 1) return;   
  8.    
  9.     if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {   
  10.         if (impl->mStrong == INITIAL_STRONG_VALUE)   
  11.             delete impl->mBase;   
  12.         else {   
  13. //            LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);   
  14.             delete impl;   
  15.         }   
  16.     } else {   
  17.         impl->mBase->onLastWeakRef(id);   
  18.         if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {   
  19.             delete impl->mBase;   
  20.         }   
  21.     }   
  22. }   

    这里又一次调用了weakref_impl对象的removeWeakRef函数,这也是和RefBase::weakref_type::incWeak函数里面的impl->addWeakRef语句所对应的,实现弱引用计数减1的操作是下面语句:const int32_t c = android_atomic_dec(&impl->mWeak);  

 减1前如果发现不等于1,那么就什么也不用做就返回了,如果发现等于1,就说明当前对象的弱引用计数值为0了,这时候,就要看看是否要delete这个对象了:

 
 
  1. if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {   
  2.     if (impl->mStrong == INITIAL_STRONG_VALUE)   
  3.         delete impl->mBase;   
  4.     else {   
  5. //      LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);   
  6.         delete impl;   
  7.     }   
  8. else {   
  9.     impl->mBase->onLastWeakRef(id);   
  10.     if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {   
  11.         delete impl->mBase;   
  12.     }   
  13. }   

  如果目标对象的生命周期是不受弱引用计数控制的,就执行下面语句:

 
 
  1. if (impl->mStrong == INITIAL_STRONG_VALUE)   
  2.     delete impl->mBase;   
  3. else {   
  4. //  LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);   
  5.     delete impl;   
  6. }   

     这个代码段是什么意思呢?这里是减少对象的弱引用计数的地方,如果调用到这里,那么就说明前面一定有增加过此对象的弱引用计数,而增加对象的弱引用计数有两种场景的,一种场景是增加对象的强引用计数的时候,会同时增加对象的弱引用计数,另一种场景是当我们使用一个弱指针来指向对象时,在弱指针对象的构造函数里面,也会增加对象的弱引用计数,不过这时候,就只是增加对象的弱引用计数了,并没有同时增加对象的强引用计数。因此,这里在减少对象的弱引用计数时,就要分两种情况来考虑。

 

        如果是前一种场景,这里的impl->mStrong就必然等于0,而不会等于INITIAL_STRONG_VALUE值,因此,这里就不需要delete目标对象了(impl->mBase),因为前面的RefBase::decStrong函数会负责delete这个对象。这里唯一需要做的就是把weakref_impl对象delete掉,但是,为什么要在这里delete这个weakref_impl对象呢?这里的weakref_impl对象是在RefBase的构造函数里面new出来的,理论上说应该在在RefBase的析构函数里delete掉这个weakref_impl对象的。在RefBase的析构函数里面,的确是会做这件事情:

 
 
  1. RefBase::~RefBase()   
  2. {   
  3. //    LOGV("Destroying RefBase %p (refs %p)\n", this, mRefs);   
  4.     if (mRefs->mWeak == 0) {   
  5. //        LOGV("Freeing refs %p of old RefBase %p\n", mRefs, this);   
  6.         delete mRefs;   
  7.     }   
  8. }   

   但是不要忘记,在这个场景下,目标对象是前面的RefBase::decStrong函数delete掉的,这时候目标对象就会被析构,但是它的弱引用计数值尚未执行减1操作,因此,这里的mRefs->mWeak == 0条件就不成立,于是就不会delete这个weakref_impl对象,因此,就延迟到执行这里decWeak函数时再执行。 

如果是后一种情景,这里的impl->mStrong值就等于INITIAL_STRONG_VALUE了,这时候由于没有地方会负责delete目标对象,因此,就需要把目标对象(imp->mBase)delete掉了,否则就会造成内存泄漏。在delete这个目标对象的时候,就会执行RefBase类的析构函数,这时候目标对象的弱引用计数等于0,于是,就会把weakref_impl对象也一起delete掉了。





本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966562,如需转载请自行联系原作者

目录
相关文章
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
1608 4
|
9月前
|
Linux 测试技术 语音技术
【车载Android】模拟Android系统的高负载环境
本文介绍如何将Linux压力测试工具Stress移植到Android系统,用于模拟高负载环境下的CPU、内存、IO和磁盘压力,帮助开发者优化车载Android应用在多任务并发时的性能问题,提升系统稳定性与用户体验。
745 6
|
9月前
|
Java 数据库 Android开发
基于Android的电子记账本系统
本项目研究开发一款基于Java与Android平台的开源电子记账系统,采用SQLite数据库和Gradle工具,实现高效、安全、便捷的个人财务管理,顺应数字化转型趋势。
|
安全 搜索推荐 Android开发
Android系统SELinux安全机制详解
如此看来,SELinux对于大家来说,就像那位不眠不休,严阵以待的港口管理员,守护我们安卓系统的平安,维护这片海港的和谐生态。SELinux就这样,默默无闻,却卫士如山,给予Android系统一份厚重的安全保障。
472 18
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
1173 38
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
1079 21
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
290 8
|
安全 Android开发 iOS开发
深入探讨Android与iOS系统的差异及未来发展趋势
本文旨在深入分析Android和iOS两大移动操作系统的核心技术差异、用户体验以及各自的市场表现,进一步探讨它们在未来技术革新中可能的发展方向。通过对比两者的开放性、安全性、生态系统等方面,本文揭示了两大系统在移动设备市场中的竞争态势和潜在变革。

热门文章

最新文章