我是靠谱客的博主 难过小懒虫,最近开发中收集的这篇文章主要介绍Android系统的智能指针 轻量级指针 强指针和弱指针 的实现原理分析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

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

《Android系统源代码情景分析》一书正在进击的程序员网(http://0xcc0xcd.com)中连载,点击进入!

        在使用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文件中:

template <class T>class LightRefBase{publicinline LightRefBase() : mCount(0) { } inline void incStrong(const void* id) const {  android_atomic_inc(&mCount); } inline void decStrong(const void* id) const {  if (android_atomic_dec(&mCount) == 1) {   delete static_cast<const T*>(this);  } } //! DEBUGGING ONLY: Get current strong ref count. inline int32_t getStrongCount() const {  return mCount; }protectedinline ~LightRefBase() { }privatemutable volatile int32_t mCount;};
         这个类很简单,它只一个成员变量mCount,这就是引用计数器了,它的初始化值为0,另外,这个类还提供两个成员函数incStrong和decStrong来维护引用计数器的值,这两个函数就是提供给智能指针来调用的了,这里要注意的是,在decStrong函数中,如果当前引用计数值为1,那么当减1后就会变成0,于是就会delete这个对象。

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

template <typename T>class sp{publictypedef typename RefBase::weakref_type weakref_type; inline sp() : m_ptr(0) { } sp(T* other); sp(const sp<T>& other); template<typename U> sp(U* other); template<typename U> sp(const sp<U>& other); ~sp(); // Assignment sp& operator = (T* other); sp& operator = (const sp<T>& other); template<typename U> sp& operator = (const sp<U>& other); template<typename U> sp& operator = (U* other); //! Special optimization for use by ProcessState (and nobody else). void force_set(T* other)// Reset void clear()// Accessors inline  T&      operator* () const  { return *m_ptr; } inline  T*      operator-> () const { return m_ptr;  } inline  T*      get() const         { return m_ptr; } // Operators COMPARE(==)  COMPARE(!=)  COMPARE(>)  COMPARE(<)  COMPARE(<=)  COMPARE(>=)privatetemplate<typename Y> friend class sp; template<typename Y> friend class wp; // Optimization for wp::promote(). sp(T* p, weakref_type* refs); T*              m_ptr;};
        这个类的内容比较多,但是这里我们只关注它的成员变量m_ptr、构造函数和析构函数。不难看出,成员变量m_ptr就是指向真正的对象了,它是在构造函数里面初始化的。接下来我们就再看一下它的两个构造函数,一个是普通构造函数,一个拷贝构造函数:

template<typename T>sp<T>::sp(T* other)    : m_ptr(other){    if (other) other->incStrong(this);}template<typename T>sp<T>::sp(const sp<T>& other)    : m_ptr(other.m_ptr){    if (m_ptr) m_ptr->incStrong(this);}
        这两个构造函数都会首先初始化成员变量m_ptr,然后再调用m_ptr的incStrong函数来增加对象的引用计数,在我们这个场景中,就是调用LightRefBase类的incStrong函数了。

        最后,看一下析构函数:

template<typename T>sp<T>::~sp(){    if (m_ptr) m_ptr->decStrong(this);}
        析构函数也很简单,只是调用m_ptr的成员函数decStrong来减少对象的引用计数值,这里就是调用LightRefBase类的decStrong函数了,前面我们看到,当这个引用计数减1后变成0时,就会自动delete这个对象了。

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

        2. 轻量级指针的用法

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

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

#include <stdio.h>#include <utils/RefBase.h>using namespace android;class LightClass : public LightRefBase<LightClass>{public:        LightClass()        {                printf("Construct LightClass Object.");        }        virtual ~LightClass()        {                printf("Destory LightClass Object.");        }};int main(int argc, char** argv){        LightClass* pLightClass = new LightClass();        sp<LightClass> lpOut = pLightClass;        printf("Light Ref Count: %d.n", pLightClass->getStrongCount());        {                sp<LightClass> lpInner = lpOut;                printf("Light Ref Count: %d.n", pLightClass->getStrongCount());        }        printf("Light Ref Count: %d.n", pLightClass->getStrongCount());        return 0;}
        我们创建一个自己的类LightClass,继承了LightRefBase模板类,这样类LightClass就具有引用计数的功能了。在main函数里面,我们首先new一个LightClass对象,然后把这个对象赋值给智能指针lpOut,这时候通过一个printf语句来将当前对象的引用计数值打印出来,从前面的分析可以看出,如果一切正常的话,这里打印出来的引用计数值为1。接着,我们又在两个大括号里面定义了另外一个智能指针lpInner,它通过lpOut间接地指向了前面我们所创建的对象,这时候再次将当前对象的引用计数值打印出来,从前面 的分析也可以看出,如果一切正常的话,这里打印出来的引用计数值应该为2。程序继承往下执行,当出了大括号的范围的时候,智能指针对象lpInner就被析构了,从前面的分析可以知道,智能指针在析构的时候,会减少当前对象的引用计数值,因此,最后一个printf语句打印出来的引用计数器值应该为1。当main函数执行完毕后,智能指针lpOut也会被析构,被析构时,它会再次减少当前对象的引用计数,这时候,对象的引用计数值就为0了,于是,它就会被delete了。

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

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optionalLOCAL_MODULE := lightpointerLOCAL_SRC_FILES := lightpointer.cppLOCAL_SHARED_LIBRARIES :=         libcutils         libutilsinclude $(BUILD_EXECUTABLE)
        最后,我们参照 如何单独编译Android源代码中的模块一文,使用mmm命令对工程进行编译:
USER-NAME@MACHINE-NAME:~/Android$ mmm ./external/lightpointer
        编译之后,就可以打包了:

USER-NAME@MACHINE-NAME:~/Android$ make snod
        最后得到可执行程序lightpointer就位于设备上的/system/bin/目录下。启动模拟器,通过adb shell命令进入到模拟器终端,进入到/system/bin/目录,执行lightpointer可执行程序,验证程序是否按照我们设计的逻辑运行:
USER-NAME@MACHINE-NAME:~/Android$ adb shellroot@android:/ # cd system/bin/        root@android:/system/bin # ./lightpointer                                      Construct LightClass Object.Light Ref Count: 1.Light Ref Count: 2.Light Ref Count: 1.Destory LightClass Object.

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

       3. 强指针

       强指针所使用的引用计数类为RefBase,它LightRefBase类要复杂多了,所以才称后者为轻量级的引用计数基类吧。我们先来看看RefBase类的实现,它定义在frameworks/base/include/utils/RefBase.h文件中:

class RefBase{publicvoid            incStrong(const void* id) constvoid            decStrong(const void* id) constvoid            forceIncStrong(const void* id) const//! DEBUGGING ONLY: Get current strong ref count. int32_t         getStrongCount() constclass weakref_type { public:  RefBase*            refBase() const;  void                incWeak(const void* id);  void                decWeak(const void* id);  bool                attemptIncStrong(const void* id);  //! This is only safe if you have set OBJECT_LIFETIME_FOREVER.  bool                attemptIncWeak(const void* id);  //! DEBUGGING ONLY: Get current weak ref count.  int32_t             getWeakCount() const;  //! DEBUGGING ONLY: Print references held on object.  void                printRefs() const;  //! DEBUGGING ONLY: Enable tracking for this object.  // enable -- enable/disable tracking  // retain -- when tracking is enable, if true, then we save a stack trace  //           for each reference and dereference; when retain == false, we  //           match up references and dereferences and keep only the   //           outstanding ones.  void                trackMe(bool enable, bool retain); }; weakref_type*   createWeak(const void* id) constweakref_type*   getWeakRefs() const//! DEBUGGING ONLY: Print references held on object. inline  void            printRefs() const { getWeakRefs()->printRefs(); } //! DEBUGGING ONLY: Enable tracking of object. inline  void            trackMe(bool enable, bool retain) {  getWeakRefs()->trackMe(enable, retain); }protected: RefBase(); virtual                 ~RefBase(); //! Flags for extendObjectLifetime() enum {  OBJECT_LIFETIME_WEAK    = 0x0001,  OBJECT_LIFETIME_FOREVER = 0x0003 }; void            extendObjectLifetime(int32_t mode)//! Flags for onIncStrongAttempted() enum {  FIRST_INC_STRONG = 0x0001 }; virtual void            onFirstRef()virtual void            onLastStrongRef(const void* id)virtual bool            onIncStrongAttempted(uint32_t flags, const void* id)virtual void            onLastWeakRef(const void* id);privatefriend class weakref_type; class weakref_impl; RefBase(const RefBase& o); RefBase&        operator=(const RefBase& o); weakref_impl* const mRefs;};
        RefBase类和LightRefBase类一样,提供了incStrong和decStrong成员函数来操作它的引用计数器;而RefBase类与LightRefBase类最大的区别是,它不像LightRefBase类一样直接提供一个整型值(mutable volatile int32_t mCount)来维护对象的引用计数,前面我们说过,复杂的引用计数技术同时支持强引用计数和弱引用计数,在RefBase类中,这两种计数功能是通过其成员变量mRefs来提供的。

        RefBase类的成员变量mRefs的类型为weakref_impl指针,它实现在frameworks/base/libs/utils/RefBase.cpp文件中:

class RefBase::weakref_impl : public RefBase::weakref_type{publicvolatile int32_t    mStrong; volatile int32_t    mWeak; RefBase* const      mBase; volatile int32_t    mFlags;#if !DEBUG_REFS weakref_impl(RefBase* base)  : mStrong(INITIAL_STRONG_VALUE)  , mWeak(0)  , mBase(base)  , mFlags(0) { } void addStrongRef(const void* /*id*/) { } void removeStrongRef(const void* /*id*/) { } void addWeakRef(const void* /*id*/) { } void removeWeakRef(const void* /*id*/) { } void printRefs() const { } void trackMe(bool, bool) { }#else weakref_impl(RefBase* base)  : mStrong(INITIAL_STRONG_VALUE)  , mWeak(0)  , mBase(base)  , mFlags(0)  , mStrongRefs(NULL)  , mWeakRefs(NULL)  , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)  , mRetain(false) {  //LOGI("NEW weakref_impl %p for RefBase %p", this, base); } ~weakref_impl() {  LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!");  LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!"); } void addStrongRef(const void* id) {  addRef(&mStrongRefs, id, mStrong); } void removeStrongRef(const void* id) {  if (!mRetain)   removeRef(&mStrongRefs, id);  else   addRef(&mStrongRefs, id, -mStrong); } void addWeakRef(const void* id) {  addRef(&mWeakRefs, id, mWeak); } void removeWeakRef(const void* id) {  if (!mRetain)   removeRef(&mWeakRefs, id);  else   addRef(&mWeakRefs, id, -mWeak); } void trackMe(bool track, bool retain) {  mTrackEnabled = track;  mRetain = retain; } ......privatestruct ref_entry {  ref_entry* next;  const void* id;#if DEBUG_REFS_CALLSTACK_ENABLED  CallStack stack;#endif  int32_t ref; }; void addRef(ref_entry** refs, const void* id, int32_t mRef) {  if (mTrackEnabled) {   AutoMutex _l(mMutex);   ref_entry* ref = new ref_entry;   // Reference count at the time of the snapshot, but before the   // update.  Positive value means we increment, negative--we   // decrement the reference count.   ref->ref = mRef;   ref->id = id;#if DEBUG_REFS_CALLSTACK_ENABLED   ref->stack.update(2);#endif   ref->next = *refs;   *refs = ref;  } } void removeRef(ref_entry** refs, const void* id) {  if (mTrackEnabled) {   AutoMutex _l(mMutex);   ref_entry* ref = *refs;   while (ref != NULL) {    if (ref->id == id) {     *refs = ref->next;     delete ref;     return;    }    refs = &ref->next;    ref = *refs;   }   LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",    id, mBase, this);  } } ...... Mutex mMutex; ref_entry* mStrongRefs; ref_entry* mWeakRefs; bool mTrackEnabled; // Collect stack traces on addref and removeref, instead of deleting the stack references // on removeref that match the address ones. bool mRetain; ......#endif};
        这个类看起来实现得很复杂,其实不然,这个类的实现可以分成两部分:

#if !DEBUG_REFS......#else
        编译指令之间的这部分源代码是Release版本的源代码,它的成员函数都是空实现;

#else ......#endif
        编译指令之间的部分源代码是Debug版本的源代码,它的成员函数都是有实现的,实现这些函数的目的都是为了方便开发人员调试引用计数用的,除此之外,还在内部实现了一个结构体ref_entry:

struct ref_entry{ ref_entry* next; const void* id;#if DEBUG_REFS_CALLSTACK_ENABLED CallStack stack;#endif int32_t ref;};
        这个结构体也是为了方便调试而使用的,我们可以不关注这部分用于调试的代码。

        总的来说,weakref_impl类只要提供了以下四个成员变量来维护对象的引用计数:

volatile int32_t    mStrong;volatile int32_t    mWeak;RefBase* const      mBase;volatile int32_t    mFlags;
        其中mStrong和mWeak分别表示对象的强引用计数和弱引用计数;RefBase类包含了一个weakref_impl类指针mRefs,而这里的weakref_impl类也有一个成员变量mBase来指向它的宿主类RefBase;mFlags是一个标志位,它指示了维护对象引用计数所使用的策略,后面我们将会分析到,它的取值为0,或者以下的枚举值:

//! Flags for extendObjectLifetime()    enum {        OBJECT_LIFETIME_WEAK    = 0x0001,        OBJECT_LIFETIME_FOREVER = 0x0003    };
        这里我们还需要注意的一点的是,从weakref_impl的类名来看,它应该是一个实现类,那么,就必然有一个对应的接口类,这个对应的接口类的就是RefBase类内部定义的weakref_type类了,这是一种把类的实现与接口定义分离的设计方法。学习过设计模式的读者应该知道,在设计模式里面,非常强调类的接口定义和类的实现分离,以便利于后续扩展和维护,这里就是用到了这种设计思想。

        说了这多,RefBase类给人的感觉还是挺复杂的,不要紧,我们一步步来,先通过下面这个图来梳理一下这些类之间的关系:


        从这个类图可以看出,每一个RefBase对象包含了一个weakref_impl对象,而weakref_impl对象实现了weakref_type接口,同时它可以包含多个ref_entry对象,前面说过,ref_entry是调试用的一个结构体,实际使用中可以不关注。

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

template<typename T>sp<T>::sp(T* other)    : m_ptr(other){    if (other) other->incStrong(this);}

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

void RefBase::incStrong(const void* id) const{    weakref_impl* const refs = mRefs;    refs->addWeakRef(id);    refs->incWeak(id);    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=%dn", this, id, c);    #endif     if (c != INITIAL_STRONG_VALUE) {         return;     }     android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);     const_cast<RefBase*>(this)->onFirstRef();}

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

RefBase::RefBase()    : mRefs(new weakref_impl(this)){//    LOGV("Creating refs %p with RefBase %pn", mRefs, this);}
        在这个incStrong函数中,主要做了三件事情:

        一是增加弱引用计数:

refs->addWeakRef(id);refs->incWeak(id);
        二是增加强引用计数:
refs->addStrongRef(id);const int32_t c = android_atomic_inc(&refs->mStrong);
        三是如果发现是首次调用这个对象的incStrong函数,就会调用一个这个对象的onFirstRef函数,让对象有机会在对象被首次引用时做一些处理逻辑:
if (c != INITIAL_STRONG_VALUE)  {    return;}android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);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函数:

void RefBase::weakref_type::incWeak(const void* id){    weakref_impl* const impl = static_cast<weakref_impl*>(this);    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);}
       增加弱引用计数是下面语句执行的:
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。

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

template<typename T>sp<T>::~sp(){    if (m_ptr) m_ptr->decStrong(this);}
       同样,这里的m_ptr指向的目标对象一定是继承了RefBase类的,因此,这里调用的是 RefBase类的decStrong函数,这也是定义在frameworks/base/libs/utils/RefBase.cpp文件中:

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=%dn", 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);        if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {            delete this;        }    }    refs->removeWeakRef(id);    refs->decWeak(id);}
        这里的refs->removeStrongRef函数调用语句是对应前面在RefBase::incStrong函数里的refs->addStrongRef函数调用语句的,在Release版本中,这也是一个空实现函数,真正实现强引用计数减1的操作是下面语句:
const int32_t c = android_atomic_dec(&refs->mStrong);
        如果发现减1前,此对象的强引用计数为1,就说明从此以后,就再没有地方引用这个目标对象了,这时候,就要看看是否要delete这个目标对象了:

if (c == 1) {    const_cast<RefBase*>(this)->onLastStrongRef(id);    if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {        delete this;    }}
        在强引用计数为0的情况下,如果对象的标志位OBJECT_LIFETIME_WEAK被设置了,就说明这个对象的生命周期是受弱引用计数所控制的,因此,这时候就不能delete对象,要等到弱引用计数也为0的情况下,才能delete这个对象。

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

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;    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {        if (impl->mStrong == INITIAL_STRONG_VALUE)            delete impl->mBase;        else {//            LOGV("Freeing refs %p of old RefBase %pn", this, impl->mBase);            delete impl;        }    } else {        impl->mBase->onLastWeakRef(id);        if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {            delete impl->mBase;        }    }}
       这里又一次调用了weakref_impl对象的removeWeakRef函数,这也是和RefBase::weakref_type::incWeak函数里面的impl->addWeakRef语句所对应的,实现弱引用计数减1的操作是下面语句:

const int32_t c = android_atomic_dec(&impl->mWeak);
       减1前如果发现不等于1,那么就什么也不用做就返回了,如果发现等于1,就说明当前对象的弱引用计数值为0了,这时候,就要看看是否要delete这个对象了:

if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {    if (impl->mStrong == INITIAL_STRONG_VALUE)        delete impl->mBase;    else {//      LOGV("Freeing refs %p of old RefBase %pn", this, impl->mBase);        delete impl;    }} else {    impl->mBase->onLastWeakRef(id);    if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {        delete impl->mBase;    }}
        如果目标对象的生命周期是不受弱引用计数控制的,就执行下面语句:

if (impl->mStrong == INITIAL_STRONG_VALUE)    delete impl->mBase;else {//  LOGV("Freeing refs %p of old RefBase %pn", this, impl->mBase);    delete impl;}
        这个代码段是什么意思呢?这里是减少对象的弱引用计数的地方,如果调用到这里,那么就说明前面一定有增加过此对象的弱引用计数,而增加对象的弱引用计数有两种场景的,一种场景是增加对象的强引用计数的时候,会同时增加对象的弱引用计数,另一种场景是当我们使用一个弱指针来指向对象时,在弱指针对象的构造函数里面,也会增加对象的弱引用计数,不过这时候,就只是增加对象的弱引用计数了,并没有同时增加对象的强引用计数。因此,这里在减少对象的弱引用计数时,就要分两种情况来考虑。

        如果是前一种场景,这里的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的析构函数里面,的确是会做这件事情:

RefBase::~RefBase(){//    LOGV("Destroying RefBase %p (refs %p)n", this, mRefs);    if (mRefs->mWeak == 0) {//        LOGV("Freeing refs %p of old RefBase %pn", mRefs, this);        delete mRefs;    }}

        但是不要忘记,在这个场景下,目标对象是前面的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掉了。

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

impl->mBase->onLastWeakRef(id);if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {    delete impl->mBase;}
        理论上说,如果目标对象的生命周期是受 弱引用计数控制的,那么当强引用计数和弱引用计数都为0的时候,这时候就应该delete目标对象了,但是这里还有另外一层控制,我们可以设置目标对象的标志值为OBJECT_LIFETIME_FOREVER,即目标对象的生命周期完全不受强引用计数和弱引用计数控制,在这种情况下,即使目标对象的强引用计数和弱引用计数都同时为0,这里也不能delete这个目标对象,那么,由谁来delete掉呢?当然是谁new出来的,就谁来delete掉了,这时候智能指针就完全退化为普通指针了,这里的智能指针设计的非常强大。

        分析到这里,有必要小结一下:

        A. 如果对象的标志位被设置为0,那么只要发现对象的强引用计数值为0,那就会自动delete掉这个对象;

        B. 如果对象的标志位被设置为OBJECT_LIFETIME_WEAK,那么只有当对象的强引用计数和弱引用计数都为0的时候,才会自动delete掉这个对象;

        C. 如果对象的标志位被设置为OBJECT_LIFETIME_FOREVER,那么对象就永远不会自动被delete掉,谁new出来的对象谁来delete掉。

        到了这里,强指针就分析完成了,最后来分析弱指针。

        4. 弱指针

        弱指针所使用的引用计数类与强指针一样,都是RefBase类,因此,这里就不再重复介绍了,我们直接来弱指针的实现,它定义在frameworks/base/include/utils/RefBase.h文件中:

template <typename T>class wp{publictypedef typename RefBase::weakref_type weakref_type; inline wp() : m_ptr(0) { } wp(T* other); wp(const wp<T>& other); wp(const sp<T>& other); template<typename U> wp(U* other); template<typename U> wp(const sp<U>& other); template<typename U> wp(const wp<U>& other); ~wp(); // Assignment wp& operator = (T* other); wp& operator = (const wp<T>& other); wp& operator = (const sp<T>& other); template<typename U> wp& operator = (U* other); template<typename U> wp& operator = (const wp<U>& other); template<typename U> wp& operator = (const sp<U>& other); void set_object_and_refs(T* other, weakref_type* refs)// promotion to sp sp<T> promote() const// Reset void clear()// Accessors inline  weakref_type* get_refs() const { return m_refs; } inline  T* unsafe_get() const { return m_ptr; } // Operators COMPARE_WEAK(==)  COMPARE_WEAK(!=)  COMPARE_WEAK(>)  COMPARE_WEAK(<)  COMPARE_WEAK(<=)  COMPARE_WEAK(>=)  inline bool operator == (const wp<T>& o) const {   return (m_ptr == o.m_ptr) && (m_refs == o.m_refs); } template<typename U> inline bool operator == (const wp<U>& o) const {  return m_ptr == o.m_ptr; } inline bool operator > (const wp<T>& o) const {  return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr); } template<typename U> inline bool operator > (const wp<U>& o) const {  return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr); } inline bool operator < (const wp<T>& o) const {  return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr); } template<typename U> inline bool operator < (const wp<U>& o) const {  return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr); } inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; } template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); } inline bool operator <= (const wp<T>& o) const { return !operator > (o); } template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); } inline bool operator >= (const wp<T>& o) const { return !operator < (o); } template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }privatetemplate<typename Y> friend class sp; template<typename Y> friend class wp; T*              m_ptr; weakref_type*   m_refs;};
        与强指针类相比,它们都有一个成员变量m_ptr指向目标对象,但是弱指针还有一个额外的成员变量m_refs,它的类型是weakref_type指针,下面我们分析弱指针的构造函数时再看看它是如果初始化的。这里我们需要关注的仍然是弱指针的构造函数和析构函数。

        先来看构造函数:

template<typename T>wp<T>::wp(T* other)    : m_ptr(other){    if (other) m_refs = other->createWeak(this);}
        这里的参数other一定是继承了RefBase类,因此,这里调用了RefBase类的createWeak函数,它定义在frameworks/base/libs/utils/RefBase.cpp文件中:

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

这里写图片描述

最后

以上就是难过小懒虫为你收集整理的Android系统的智能指针 轻量级指针 强指针和弱指针 的实现原理分析的全部内容,希望文章能够帮你解决Android系统的智能指针 轻量级指针 强指针和弱指针 的实现原理分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部