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

简介:

   即如果目标对象的生命周期只受到强引用计数控制或者在目标对象的具体实现中总是允许这种情况发生。怎么理解呢?如果目标对象的生命周期只受强引用计数控制(它的标志位mFlags为0),而这时目标对象又还未被强指针引用过,它自然就不会被delete掉,因此,这时候可以判断出目标对象是存在的;如果目标对象的生命周期受弱引用计数控制(OBJECT_LIFETIME_WEAK),这时候由于目标对象正在被弱指针引用,因此,弱引用计数一定不为0,目标对象一定存在;如果目标对象的生命周期不受引用计数控制(BJECT_LIFETIME_FOREVER),这时候目标对象也是下在被弱指针引用,因此,目标对象的所有者必须保证这个目标对象还没有被delete掉,否则就会出问题了。在后面两种场景下,因为目标对象的生命周期都是不受强引用计数控制的,而现在又要把弱指针提升为强指针,就需要进一步调用目标对象的onIncStrongAttempted来看看是否允许这种情况发生,这又该怎么理解呢?可以这样理解,目标对象的设计者可能本身就不希望这个对象被强指针引用,只能通过弱指针来引用它,因此,这里它就可以重载其父类的onIncStrongAttempted函数,然后返回false,这样就可以阻止弱指针都被提升为强指针。在RefBase类中,其成员函数onIncStrongAttempted默认是返回true的:

  1. bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)  
  2. {  
  3.     return (flags&FIRST_INC_STRONG) ? true : false;  
  4. }  

   如果此时目标对象的强引用计数值小于等于0,那就说明该对象之前一定被强指针引用过,这时候就必须保证目标对象是被弱引用计数控制的(BJECT_LIFETIME_WEAK),否则的话,目标对象就已经被delete了。同样,这里也要调用一下目标对象的onIncStrongAttempted成员函数,来询问一下目标对象在强引用计数值小于等于0的时候,是否允计将弱指针提升为强指针。下面这个代码段就是执行上面所说的逻辑:

  1. allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK  
  2.     && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);  

  继续往下看:

  1. if (!allow) {  
  2.     decWeak(id);  
  3.     return false;  
  4. }  
  5. curCount = android_atomic_inc(&impl->mStrong);  

    如果allow值为false,那么就说明不允计把这个弱指针提升为强指针,因此就返回false了,在返回之前,要先调用decWeak函数来减少目标对象的弱引用计数,因为函数的开头不管三七二十一,首先就调用了incWeak来增加目标对象的弱引用计数值。

 

        函数attemptIncStrong的主体逻辑大概就是这样了,比较复杂,读者要细细体会一下。函数的最后,如果此弱指针是允计提升为强指针的,并且此目标对象是第一次被强指针引用,还需要调整一下目标对象的强引用计数值:

  1. if (curCount == INITIAL_STRONG_VALUE) {  
  2.     android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);  
  3.     impl->mBase->onFirstRef();  
  4. }  

  这个逻辑我们在前面分析强指针时已经分析过了,这里不再详述。

 

        分析到这里,弱指针就介绍完了。强指针和弱指针的关系比较密切,同时它们也比较复杂,下面我们再举一个例子来说明强指针和弱指针的用法,同时也验证一下它们的实现原理。

        5. 强指针和弱指针的用法

        我们在external目录下建立一个C++工程目录weightpointer,它里面有两个文件,一个weightpointer.cpp文件,另外一个是Android.mk文件。

        源文件weightpointer.cpp的内容如下:

 
 
  1. #include <stdio.h>   
  2. #include <utils/RefBase.h>   
  3.    
  4. #define INITIAL_STRONG_VALUE (1<<28)   
  5.    
  6. using namespace android;   
  7.    
  8. class WeightClass : public RefBase   
  9. {   
  10. public:   
  11.         void printRefCount()   
  12.         {   
  13.                 int32_t strong = getStrongCount();   
  14.                 weakref_type* ref = getWeakRefs();   
  15.    
  16.                 printf("-----------------------\n");   
  17.                 printf("Strong Ref Count: %d.\n", (strong  == INITIAL_STRONG_VALUE ? 0 : strong));   
  18.                 printf("Weak Ref Count: %d.\n", ref->getWeakCount());   
  19.                 printf("-----------------------\n");   
  20.         }   
  21. };   
  22.    
  23. class StrongClass : public WeightClass   
  24. {   
  25. public:   
  26.         StrongClass()   
  27.         {   
  28.                 printf("Construct StrongClass Object.\n");   
  29.         }   
  30.    
  31.         virtual ~StrongClass()   
  32.         {   
  33.                 printf("Destory StrongClass Object.\n");   
  34.         }   
  35. };   
  36.    
  37.    
  38. class WeakClass : public WeightClass   
  39. {   
  40. public:   
  41.         WeakClass()   
  42.         {   
  43.                 extendObjectLifetime(OBJECT_LIFETIME_WEAK);   
  44.    
  45.                 printf("Construct WeakClass Object.\n");   
  46.         }   
  47.    
  48.         virtual ~WeakClass()   
  49.         {   
  50.                 printf("Destory WeakClass Object.\n");   
  51.         }   
  52. };   
  53.    
  54. class ForeverClass : public WeightClass   
  55. {   
  56. public:   
  57.         ForeverClass()   
  58.         {   
  59.                 extendObjectLifetime(OBJECT_LIFETIME_FOREVER);   
  60.    
  61.                 printf("Construct ForeverClass Object.\n");   
  62.         }   
  63.    
  64.         virtual ~ForeverClass()   
  65.         {   
  66.                 printf("Destory ForeverClass Object.\n");   
  67.         }   
  68. };   
  69.    
  70.    
  71. void TestStrongClass(StrongClass* pStrongClass)   
  72. {   
  73.         wp<StrongClass> wpOut = pStrongClass;   
  74.         pStrongClass->printRefCount();   
  75.    
  76.         {   
  77.                 sp<StrongClass> spInner = pStrongClass;   
  78.                 pStrongClass->printRefCount();   
  79.         }   
  80.    
  81.         sp<StrongClass> spOut = wpOut.promote();   
  82.         printf("spOut: %p.\n", spOut.get());   
  83. }   
  84.    
  85. void TestWeakClass(WeakClass* pWeakClass)   
  86. {   
  87.         wp<WeakClass> wpOut = pWeakClass;   
  88.         pWeakClass->printRefCount();   
  89.    
  90.         {   
  91.                 sp<WeakClass> spInner = pWeakClass;   
  92.                 pWeakClass->printRefCount();   
  93.         }   
  94.    
  95.         pWeakClass->printRefCount();   
  96.         sp<WeakClass> spOut = wpOut.promote();   
  97.         printf("spOut: %p.\n", spOut.get());   
  98. }   
  99.    
  100.    
  101. void TestForeverClass(ForeverClass* pForeverClass)   
  102. {   
  103.         wp<ForeverClass> wpOut = pForeverClass;   
  104.         pForeverClass->printRefCount();   
  105.    
  106.         {   
  107.                 sp<ForeverClass> spInner = pForeverClass;   
  108.                 pForeverClass->printRefCount();   
  109.         }   
  110. }   
  111.    
  112. int main(int argc, char** argv)   
  113. {   
  114.         printf("Test Strong Class: \n");   
  115.         StrongClass* pStrongClass = new StrongClass();   
  116.         TestStrongClass(pStrongClass);   
  117.    
  118.         printf("\nTest Weak Class: \n");   
  119.         WeakClass* pWeakClass = new WeakClass();   
  120.         TestWeakClass(pWeakClass);   
  121.    
  122.         printf("\nTest Froever Class: \n");   
  123.         ForeverClass* pForeverClass = new ForeverClass();   
  124.         TestForeverClass(pForeverClass);   
  125.         pForeverClass->printRefCount();   
  126.         delete pForeverClass;   
  127.    
  128.         return 0;   
  129. }   

   首先定义了一个基类WeightClass,继承于RefBase类,它只有一个成员函数printRefCount,作用是用来输出引用计数。接着分别定义了三个类StrongClass、WeakClass和ForeverClass,其中实例化StrongClass类的得到的对象的标志位为默认值0,实例化WeakClass类的得到的对象的标志位为OBJECT_LIFETIME_WEAK,实例化ForeverClass类的得到的对象的标志位为OBJECT_LIFETIME_FOREVER,后两者都是通过调用RefBase类的extendObjectLifetime成员函数来设置的。

        在main函数里面,分别实例化了这三个类的对象出来,然后分别传给TestStrongClass函数、TestWeakClass函数和TestForeverClass函数来说明智能指针的用法,我们主要是通过考察它们的强引用计数和弱引用计数来验证智能指针的实现原理。

        编译脚本文件Android.mk的内容如下:

 
 
  1. LOCAL_PATH := $(call my-dir)   
  2. include $(CLEAR_VARS)   
  3. LOCAL_MODULE_TAGS := optional   
  4. LOCAL_MODULE := weightpointer   
  5. LOCAL_SRC_FILES := weightpointer.cpp   
  6. LOCAL_SHARED_LIBRARIES := \   
  7.         libcutils \   
  8.         libutils   
  9. include $(BUILD_EXECUTABLE)   

最后,我们参照如何单独编译Android源代码中的模块一文,使用mmm命令对工程进行编译:

  1. USER-NAME@MACHINE-NAME:~/Android$ mmm ./external/weightpointer  

        编译之后,就可以打包了:

 

  1. USER-NAME@MACHINE-NAME:~/Android$ make snod  

        最后得到可执行程序weightpointer就位于设备上的/system/bin/目录下。启动模拟器,通过adb shell命令进入到模拟器终端,进入到/system/bin/目录,执行weightpointer可执行程序,验证程序是否按照我们设计的逻辑运行:

  1. USER-NAME@MACHINE-NAME:~/Android$ adb shell  
  2. root@android:/ # cd system/bin/          
  3. root@android:/system/bin # ./weightpointer    

        执行TestStrongClass函数的输出为:

  1. Test Strong Class:   
  2. Construct StrongClass Object.  
  3. -----------------------  
  4. Strong Ref Count: 0.  
  5. Weak Ref Count: 1.  
  6. -----------------------  
  7. -----------------------  
  8. Strong Ref Count: 1.  
  9. Weak Ref Count: 2.  
  10. -----------------------  
  11. Destory StrongClass Object.  
  12. spOut: 0x0.  

 

        在TestStrongClass函数里面,首先定义一个弱批针wpOut指向从main函数传进来的StrongClass对象,这时候我们可以看到StrongClass对象的强引用计数和弱引用计数值分别为0和1;接着在一个大括号里面定义一个强指针spInner指向这个StrongClass对象,这时候我们可以看到StrongClass对象的强引用计数和弱引用计数值分别为1和2;当程序跳出了大括号之后,强指针spInner就被析构了,从上面的分析我们知道,强指针spInner析构时,会减少目标对象的强引用计数值,因为前面得到的强引用计数值为1,这里减1后,就变为0了,又由于这个StrongClass对象的生命周期只受强引用计数控制,因此,这个StrongClass对象就被delete了,这一点可以从后面的输出(“Destory StrongClass Object.”)以及试图把弱指针wpOut提升为强指针时得到的对象指针为0x0得到验证。

        执行TestWeakClass函数的输出为:

  1. Test Weak Class:   
  2. Construct WeakClass Object.  
  3. -----------------------  
  4. Strong Ref Count: 0.  
  5. Weak Ref Count: 1.  
  6. -----------------------  
  7. -----------------------  
  8. Strong Ref Count: 1.  
  9. Weak Ref Count: 2.  
  10. -----------------------  
  11. -----------------------  
  12. Strong Ref Count: 0.  
  13. Weak Ref Count: 1.  
  14. -----------------------  
  15. spOut: 0xa528.  
  16. Destory WeakClass Object.  

 

        TestWeakClass函数和TestStrongClass函数的执行过程基本一样,所不同的是当程序跳出大括号之后,虽然这个WeakClass对象的强引用计数值已经为0,但是由于它的生命周期同时受强引用计数和弱引用计数控制,而这时它的弱引用计数值大于0,因此,这个WeakClass对象不会被delete掉,这一点可以从后面试图把弱批针wpOut提升为强指针时得到的对象指针不为0得到验证。

        执行TestForeverClass函数的输出来:

  1. Test Froever Class:   
  2. Construct ForeverClass Object.  
  3. -----------------------  
  4. Strong Ref Count: 0.  
  5. Weak Ref Count: 1.  
  6. -----------------------  
  7. -----------------------  
  8. Strong Ref Count: 1.  
  9. Weak Ref Count: 2.  
  10. -----------------------  

       当执行完TestForeverClass函数返回到main函数的输出来:

  1. Test Froever Class:   
  2. Construct ForeverClass Object.  
  3. -----------------------  
  4. Strong Ref Count: 0.  
  5. Weak Ref Count: 1.  
  6. -----------------------  
  7. -----------------------  
  8. Strong Ref Count: 1.  
  9. Weak Ref Count: 2.  
  10. -----------------------  

       当执行完TestForeverClass函数返回到main函数的输出来:

  1. -----------------------  
  2. Strong Ref Count: 0.  
  3. Weak Ref Count: 0.  
  4. -----------------------  
  5. Destory ForeverClass Object.  

        这里我们可以看出,虽然这个ForeverClass对象的强引用计数和弱引用计数值均为0了,但是它不自动被delete掉,虽然由我们手动地delete这个对象,它才会被析构,这是因为这个ForeverClass对象的生命周期是既不受强引用计数值控制,也不会弱引用计数值控制。

 

        这样,从TestStrongClass、TestWeakClass和TestForeverClass这三个函数的输出就可以验证了我们上面对Android系统的强指针和弱指针的实现原理的分析。

        至此,Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理就分析完成了,它实现得很小巧但是很精致,希望读者可以通过实际操作细细体会一下。





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

目录
相关文章
|
1月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
160 4
|
1月前
|
人工智能 搜索推荐 物联网
Android系统版本演进与未来展望####
本文深入探讨了Android操作系统从诞生至今的发展历程,详细阐述了其关键版本迭代带来的创新特性、用户体验提升及对全球移动生态系统的影响。通过对Android历史版本的回顾与分析,本文旨在揭示其成功背后的驱动力,并展望未来Android可能的发展趋势与面临的挑战,为读者呈现一个既全面又具深度的技术视角。 ####
|
1月前
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
21天前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
24天前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
29 8
|
22天前
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
1月前
|
监控 Java Android开发
深入探讨Android系统的内存管理机制
本文将深入分析Android系统的内存管理机制,包括其内存分配、回收策略以及常见的内存泄漏问题。通过对这些方面的详细讨论,读者可以更好地理解Android系统如何高效地管理内存资源,从而提高应用程序的性能和稳定性。
68 16
|
28天前
|
安全 Android开发 iOS开发
深入探讨Android与iOS系统的差异及未来发展趋势
本文旨在深入分析Android和iOS两大移动操作系统的核心技术差异、用户体验以及各自的市场表现,进一步探讨它们在未来技术革新中可能的发展方向。通过对比两者的开放性、安全性、生态系统等方面,本文揭示了两大系统在移动设备市场中的竞争态势和潜在变革。
|
28天前
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
34 1
|
1月前
|
算法 JavaScript Android开发