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

简介:

  Android系统的运行时库层代码是用C++来编写的,用C++来写代码最容易出错的地方就是指针了,一旦使用不当,轻则造成内存泄漏,重则造成系统崩溃。不过系统为我们提供了智能指针,避免出现上述问题,本文将系统地分析Android系统智能指针(轻量级指针、强指针和弱指针)的实现原理。

        在使用C++来编写代码的过程中,指针使用不当造成内存泄漏一般就是因为new了一个对象并且使用完之后,忘记了delete这个对象,而造成系统崩溃一般就是因为一个地方delete了这个对象之后,其它地方还在继续使原来指向这个对象的指针。为了避免出现上述问题,一般的做法就是使用引用计数的方法,每当有一个指针指向了一个new出来的对象时,就对这个对象的引用计数增加1,每当有一个指针不再使用这个对象时,就对这个对象的引用计数减少1,每次减1之后,如果发现引用计数值为0时,那么,就要delete这个对象了,这样就避免了忘记delete对象或者这个对象被delete之后其它地方还在使用的问题了。但是,如何实现这个对象的引用计数呢?肯定不是由开发人员来手动地维护了,要开发人员时刻记住什么时候该对这个对象的引用计数加1,什么时候该对这个对象的引用计数减1,一来是不方便开发,二来是不可靠,一不小心哪里多加了一个1或者多减了一个1,就会造成灾难性的后果。这时候,智能指针就粉墨登场了。首先,智能指针是一个对象,不过这个对象代表的是另外一个真实使用的对象,当智能指针指向实际对象的时候,就是智能指针对象创建的时候,当智能指针不再指向实际对象的时候,就是智能指针对象销毁的时候,我们知道,在C++中,对象的创建和销毁时会分别自动地调用对象的构造函数和析构函数,这样,负责对真实对象的引用计数加1和减1的工作就落实到智能指针对象的构造函数和析构函数的身上了,这也是为什么称这个指针对象为智能指针的原因。

        在计算机科学领域中,提供垃圾收集(Garbage Collection)功能的系统框架,即提供对象托管功能的系统框架,例如Java应用程序框架,也是采用上述的引用计数技术方案来实现的,然而,简单的引用计数技术不能处理系统中对象间循环引用的情况。考虑这样的一个场景,系统中有两个对象A和B,在对象A的内部引用了对象B,而在对象B的内部也引用了对象A。当两个对象A和B都不再使用时,垃圾收集系统会发现无法回收这两个对象的所占据的内存的,因为系统一次只能收集一个对象,而无论系统决定要收回对象A还是要收回对象B时,都会发现这个对象被其它的对象所引用,因而就都回收不了,这样就造成了内存泄漏。这样,就要采取另外的一种引用计数技术了,即对象的引用计数同时存在强引用和弱引用两种计数,例如,Apple公司提出的Cocoa框架,当父对象要引用子对象时,就对子对象使用强引用计数技术,而当子对象要引用父对象时,就对父对象使用弱引用计数技术,而当垃圾收集系统执行对象回收工作时,只要发现对象的强引用计数为0,而不管它的弱引用计数是否为0,都可以回收这个对象,但是,如果我们只对一个对象持有弱引用计数,当我们要使用这个对象时,就不直接使用了,必须要把这个弱引用升级成为强引用时,才能使用这个对象,在转换的过程中,如果对象已经不存在,那么转换就失败了,这时候就说明这个对象已经被销毁了,不能再使用了。

       了解了这些背景知识后,我们就可以进一步学习Android系统的智能指针的实现原理了。Android系统提供了强大的智能指针技术供我们使用,这些智能指针实现方案既包括简单的引用计数技术,也包括了复杂的引用计数技术,即对象既有强引用计数,也有弱引用计数,对应地,这三种智能指针分别就称为轻量级指针(Light Pointer)、强指针(Strong Pointer)和弱指针(Weak Pointer)。无论是轻量级指针,还是强指针和弱指针,它们的实现框架都是一致的,即由对象本身来提供引用计数器,但是它不会去维护这个引用计数器的值,而是由智能指针来维护,就好比是对象提供素材,但是具体怎么去使用这些素材,就交给智能指针来处理了。由于不管是什么类型的对象,它都需要提供引用计数器这个素材,在C++中,我们就可以把这个引用计数器素材定义为一个公共类,这个类只有一个成员变量,那就是引用计数成员变量,其它提供智能指针引用的对象,都必须从这个公共类继承下来,这样,这些不同的对象就天然地提供了引用计数器给智能指针使用了。总的来说就是我们在实现智能指会的过程中,第一是要定义一个负责提供引用计数器的公共类,第二是我们要实现相应的智能指针对象类,后面我们会看到这种方案是怎么样实现的。

        接下来,我们就先介绍轻量级指针的实现原理,然后再接着介绍强指针和弱指针的实现原理。

        1. 轻量级指针

        先来看一下实现引用计数的类LightRefBase,它定义在frameworks/base/include/utils/RefBase.h文件中:

 
 
  1. template <class T>   
  2. class LightRefBase   
  3. {   
  4. public:   
  5.     inline LightRefBase() : mCount(0) { }   
  6.     inline void incStrong(const void* id) const {   
  7.         android_atomic_inc(&mCount);   
  8.     }   
  9.     inline void decStrong(const void* id) const {   
  10.         if (android_atomic_dec(&mCount) == 1) {   
  11.             delete static_cast<const T*>(this);   
  12.         }   
  13.     }   
  14.     //! DEBUGGING ONLY: Get current strong ref count.   
  15.     inline int32_t getStrongCount() const {   
  16.         return mCount;   
  17.     }   
  18.    
  19. protected:   
  20.     inline ~LightRefBase() { }   
  21.    
  22. private:   
  23.     mutable volatile int32_t mCount;   
  24. };   

这个类很简单,它只一个成员变量mCount,这就是引用计数器了,它的初始化值为0,另外,这个类还提供两个成员函数incStrong和decStrong来维护引用计数器的值,这两个函数就是提供给智能指针来调用的了,这里要注意的是,在decStrong函数中,如果当前引用计数值为1,那么当减1后就会变成0,于是就会delete这个对象。

     前面说过,要实现自动引用计数,除了要有提供引用计数器的基类外,还需要有智能指针类。在Android系统中,配合LightRefBase引用计数使用的智能指针类便是sp了,它也是定义在frameworks/base/include/utils/RefBase.h文件中:

 
 
  1. template <typename T>   
  2. class sp   
  3. {   
  4. public:   
  5.     typedef typename RefBase::weakref_type weakref_type;   
  6.    
  7.     inline sp() : m_ptr(0) { }   
  8.    
  9.     sp(T* other);   
  10.     sp(const sp<T>& other);   
  11.     template<typename U> sp(U* other);   
  12.     template<typename U> sp(const sp<U>& other);   
  13.    
  14.     ~sp();   
  15.    
  16.     // Assignment   
  17.    
  18.     sp& operator = (T* other);   
  19.     sp& operator = (const sp<T>& other);   
  20.    
  21.     template<typename U> sp& operator = (const sp<U>& other);   
  22.     template<typename U> sp& operator = (U* other);   
  23.    
  24.     //! Special optimization for use by ProcessState (and nobody else).   
  25.     void force_set(T* other);   
  26.    
  27.     // Reset   
  28.    
  29.     void clear();   
  30.    
  31.     // Accessors   
  32.    
  33.     inline  T&      operator* () const  { return *m_ptr; }   
  34.     inline  T*      operator-> () const { return m_ptr;  }   
  35.     inline  T*      get() const         { return m_ptr; }   
  36.    
  37.     // Operators   
  38.    
  39.     COMPARE(==)   
  40.         COMPARE(!=)   
  41.         COMPARE(>)   
  42.         COMPARE(<)   
  43.         COMPARE(<=)   
  44.         COMPARE(>=)   
  45.    
  46. private:   
  47.     template<typename Y> friend class sp;   
  48.     template<typename Y> friend class wp;   
  49.    
  50.     // Optimization for wp::promote().   
  51.     sp(T* p, weakref_type* refs);   
  52.    
  53.     T*              m_ptr;   
  54. };   

 

   这个类的内容比较多,但是这里我们只关注它的成员变量m_ptr、构造函数和析构函数。不难看出,成员变量m_ptr就是指向真正的对象了,它是在构造函数里面初始化的。接下来我们就再看一下它的两个构造函数,一个是普通构造函数,一个拷贝构造函数:

 
 
  1. template<typename T>   
  2. sp<T>::sp(T* other)   
  3.     : m_ptr(other)   
  4. {   
  5.     if (other) other->incStrong(this);   
  6. }   
  7.    
  8. template<typename T>   
  9. sp<T>::sp(const sp<T>& other)   
  10.     : m_ptr(other.m_ptr)   
  11. {   
  12.     if (m_ptr) m_ptr->incStrong(this);   
  13. }   

    这两个构造函数都会首先初始化成员变量m_ptr,然后再调用m_ptr的incStrong函数来增加对象的引用计数,在我们这个场景中,就是调用LightRefBase类的incStrong函数了。

        最后,看一下析构函数:

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

 

   析构函数也很简单,只是调用m_ptr的成员函数decStrong来减少对象的引用计数值,这里就是调用LightRefBase类的decStrong函数了,前面我们看到,当这个引用计数减1后变成0时,就会自动delete这个对象了。

   轻量级智能指针的实现原理大概就是这样了,比较简单,下面我们再用一个例子来说明它的用法。

        2. 轻量级指针的用法

        参考在Ubuntu上为Android系统内置C可执行程序测试Linux内核驱动程序一文,我们在external目录下建立一个C++工程目录lightpointer,它里面有两个文件,一个lightpointer.cpp文件,另外一个是Android.mk文件。

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

 
 
  1. #include <stdio.h>   
  2. #include <utils/RefBase.h>   
  3.    
  4. using namespace android;   
  5.    
  6. class LightClass : public LightRefBase<LightClass>   
  7. {   
  8. public:   
  9.         LightClass()   
  10.         {   
  11.                 printf("Construct LightClass Object.");   
  12.         }   
  13.    
  14.         virtual ~LightClass()   
  15.         {   
  16.                 printf("Destory LightClass Object.");   
  17.         }   
  18. };   
  19.    
  20. int main(int argc, char** argv)   
  21. {   
  22.         LightClass* pLightClass = new LightClass();   
  23.         sp<LightClass> lpOut = pLightClass;   
  24.    
  25.         printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());   
  26.    
  27.         {   
  28.                 sp<LightClass> lpInner = lpOut;   
  29.    
  30.                 printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());   
  31.         }   
  32.    
  33.         printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());   
  34.    
  35.         return 0;   
  36. }   

 

   我们创建一个自己的类LightClass,继承了LightRefBase模板类,这样类LightClass就具有引用计数的功能了。在main函数里面,我们首先new一个LightClass对象,然后把这个对象赋值给智能指针lpOut,这时候通过一个printf语句来将当前对象的引用计数值打印出来,从前面的分析可以看出,如果一切正常的话,这里打印出来的引用计数值为1。接着,我们又在两个大括号里面定义了另外一个智能指针lpInner,它通过lpOut间接地指向了前面我们所创建的对象,这时候再次将当前对象的引用计数值打印出来,从前面 的分析也可以看出,如果一切正常的话,这里打印出来的引用计数值应该为2。程序继承往下执行,当出了大括号的范围的时候,智能指针对象lpInner就被析构了,从前面的分析可以知道,智能指针在析构的时候,会减少当前对象的引用计数值,因此,最后一个printf语句打印出来的引用计数器值应该为1。当main函数执行完毕后,智能指针lpOut也会被析构,被析构时,它会再次减少当前对象的引用计数,这时候,对象的引用计数值就为0了,于是,它就会被delete了。

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

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

 

 最后,我们参照如何单独编译Android源代码中的模块一文,使用mmm命令对工程进行编译:USER-NAME@MACHINE-NAME:~/Android$ make snod  
  最后得到可执行程序lightpointer就位于设备上的/system/bin/目录下。启动模拟器,通过adb shell命令进入到模拟器终端,进入到/system/bin/目录,执行lightpointer可执行程序,验证程序是否按照我们设计的逻辑运行:

  1. USER-NAME@MACHINE-NAME:~/Android$ adb shell  
  2. root@android:/ # cd system/bin/          
  3. root@android:/system/bin # ./lightpointer                                        
  4. Construct LightClass Object.  
  5. Light Ref Count: 1.  
  6. Light Ref Count: 2.  
  7. Light Ref Count: 1.  
  8. Destory LightClass Object.  

   这里可以看出,程序一切都是按照我们的设计来运行,这也验证了我们上面分析的轻量级智能指针的实现原理。





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

目录
相关文章
|
1月前
|
人工智能 搜索推荐 物联网
Android系统版本演进与未来展望####
本文深入探讨了Android操作系统从诞生至今的发展历程,详细阐述了其关键版本迭代带来的创新特性、用户体验提升及对全球移动生态系统的影响。通过对Android历史版本的回顾与分析,本文旨在揭示其成功背后的驱动力,并展望未来Android可能的发展趋势与面临的挑战,为读者呈现一个既全面又具深度的技术视角。 ####
|
1月前
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
21天前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
22天前
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
1月前
|
监控 Java Android开发
深入探讨Android系统的内存管理机制
本文将深入分析Android系统的内存管理机制,包括其内存分配、回收策略以及常见的内存泄漏问题。通过对这些方面的详细讨论,读者可以更好地理解Android系统如何高效地管理内存资源,从而提高应用程序的性能和稳定性。
68 16
|
28天前
|
安全 Android开发 iOS开发
深入探讨Android与iOS系统的差异及未来发展趋势
本文旨在深入分析Android和iOS两大移动操作系统的核心技术差异、用户体验以及各自的市场表现,进一步探讨它们在未来技术革新中可能的发展方向。通过对比两者的开放性、安全性、生态系统等方面,本文揭示了两大系统在移动设备市场中的竞争态势和潜在变革。
|
1月前
|
算法 JavaScript Android开发
|
1月前
|
安全 搜索推荐 Android开发
揭秘安卓与iOS系统的差异:技术深度对比
【10月更文挑战第27天】 本文深入探讨了安卓(Android)与iOS两大移动操作系统的技术特点和用户体验差异。通过对比两者的系统架构、应用生态、用户界面、安全性等方面,揭示了为何这两种系统能够在市场中各占一席之地,并为用户提供不同的选择。文章旨在为读者提供一个全面的视角,理解两种系统的优势与局限,从而更好地根据自己的需求做出选择。
108 2
|
1月前
|
安全 搜索推荐 程序员
深入探索Android系统的碎片化问题及其解决方案
在移动操作系统的世界中,Android以其开放性和灵活性赢得了广泛的市场份额。然而,这种开放性也带来了一个众所周知的问题——系统碎片化。本文旨在探讨Android系统碎片化的现状、成因以及可能的解决方案,为开发者和用户提供一种全新的视角来理解这一现象。通过分析不同版本的Android系统分布、硬件多样性以及更新机制的影响,我们提出了一系列针对性的策略,旨在减少碎片化带来的影响,提升用户体验。
|
1月前
|
安全 Android开发 iOS开发
深入探索iOS与Android系统的差异性及优化策略
在当今数字化时代,移动操作系统的竞争尤为激烈,其中iOS和Android作为市场上的两大巨头,各自拥有庞大的用户基础和独特的技术特点。本文旨在通过对比分析iOS与Android的核心差异,探讨各自的优势与局限,并提出针对性的优化策略,以期为用户提供更优质的使用体验和为开发者提供有价值的参考。