Android中的sp和wp指针

来源:互联网 发布:java 日期在线转换 编辑:程序博客网 时间:2024/05/17 09:28

根据几篇文章转载

http://blog.csdn.net/luoshengyang/article/details/6786239

 

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

分类: Android 11383人阅读 评论(30) 收藏 举报

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

[cpp] view plaincopy
  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文件中:

[cpp] view plaincopy
  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就是指向真正的对象了,它是在构造函数里面初始化的。接下来我们就再看一下它的两个构造函数,一个是普通构造函数,一个拷贝构造函数:

[cpp] view plaincopy
  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函数了。

        最后,看一下析构函数:

[cpp] view plaincopy
  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的内容如下:

[cpp] view plaincopy
  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的内容如下:

[plain] view plaincopy
  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命令对工程进行编译:
[plain] view plaincopy
  1. USER-NAME@MACHINE-NAME:~/Android$ mmm ./external/lightpointer  
        编译之后,就可以打包了:

[plain] view plaincopy
  1. USER-NAME@MACHINE-NAME:~/Android$ make snod  
        最后得到可执行程序lightpointer就位于设备上的/system/bin/目录下。启动模拟器,通过adb shell命令进入到模拟器终端,进入到/system/bin/目录,执行lightpointer可执行程序,验证程序是否按照我们设计的逻辑运行:
[plain] view plaincopy
  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.  

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

       3. 强指针

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

[cpp] view plaincopy
  1. class RefBase  
  2. {  
  3. public:  
  4.     void            incStrong(const void* id) const;  
  5.     void            decStrong(const void* id) const;  
  6.   
  7.     void            forceIncStrong(const void* id) const;  
  8.   
  9.     //! DEBUGGING ONLY: Get current strong ref count.  
  10.     int32_t         getStrongCount() const;  
  11.   
  12.     class weakref_type  
  13.     {  
  14.     public:  
  15.         RefBase*            refBase() const;  
  16.   
  17.         void                incWeak(const void* id);  
  18.         void                decWeak(const void* id);  
  19.   
  20.         bool                attemptIncStrong(const void* id);  
  21.   
  22.         //! This is only safe if you have set OBJECT_LIFETIME_FOREVER.  
  23.         bool                attemptIncWeak(const void* id);  
  24.   
  25.         //! DEBUGGING ONLY: Get current weak ref count.  
  26.         int32_t             getWeakCount() const;  
  27.   
  28.         //! DEBUGGING ONLY: Print references held on object.  
  29.         void                printRefs() const;  
  30.   
  31.         //! DEBUGGING ONLY: Enable tracking for this object.  
  32.         // enable -- enable/disable tracking  
  33.         // retain -- when tracking is enable, if true, then we save a stack trace  
  34.         //           for each reference and dereference; when retain == false, we  
  35.         //           match up references and dereferences and keep only the   
  36.         //           outstanding ones.  
  37.   
  38.         void                trackMe(bool enable, bool retain);  
  39.     };  
  40.   
  41.     weakref_type*   createWeak(const void* id) const;  
  42.   
  43.     weakref_type*   getWeakRefs() const;  
  44.   
  45.     //! DEBUGGING ONLY: Print references held on object.  
  46.     inline  void            printRefs() const { getWeakRefs()->printRefs(); }  
  47.   
  48.     //! DEBUGGING ONLY: Enable tracking of object.  
  49.     inline  void            trackMe(bool enable, bool retain)  
  50.     {  
  51.         getWeakRefs()->trackMe(enable, retain);  
  52.     }  
  53.   
  54. protected:  
  55.     RefBase();  
  56.     virtual                 ~RefBase();  
  57.   
  58.     //! Flags for extendObjectLifetime()  
  59.     enum {  
  60.         OBJECT_LIFETIME_WEAK    = 0x0001,  
  61.         OBJECT_LIFETIME_FOREVER = 0x0003  
  62.     };  
  63.   
  64.     void            extendObjectLifetime(int32_t mode);  
  65.   
  66.     //! Flags for onIncStrongAttempted()  
  67.     enum {  
  68.         FIRST_INC_STRONG = 0x0001  
  69.     };  
  70.   
  71.     virtual void            onFirstRef();  
  72.     virtual void            onLastStrongRef(const void* id);  
  73.     virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);  
  74.     virtual void            onLastWeakRef(const void* id);  
  75.   
  76. private:  
  77.     friend class weakref_type;  
  78.     class weakref_impl;  
  79.   
  80.     RefBase(const RefBase& o);  
  81.     RefBase&        operator=(const RefBase& o);  
  82.   
  83.     weakref_impl* const mRefs;  
  84. };  
        RefBase类和LightRefBase类一样,提供了incStrong和decStrong成员函数来操作它的引用计数器;而RefBase类与LightRefBase类最大的区别是,它不像LightRefBase类一样直接提供一个整型值(mutable volatile int32_t mCount)来维护对象的引用计数,前面我们说过,复杂的引用计数技术同时支持强引用计数和弱引用计数,在RefBase类中,这两种计数功能是通过其成员变量mRefs来提供的。

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

[cpp] view plaincopy
  1. class RefBase::weakref_impl : public RefBase::weakref_type  
  2. {  
  3. public:  
  4.     volatile int32_t    mStrong;  
  5.     volatile int32_t    mWeak;  
  6.     RefBase* const      mBase;  
  7.     volatile int32_t    mFlags;  
  8.   
  9.   
  10. #if !DEBUG_REFS  
  11.   
  12.     weakref_impl(RefBase* base)  
  13.         : mStrong(INITIAL_STRONG_VALUE)  
  14.         , mWeak(0)  
  15.         , mBase(base)  
  16.         , mFlags(0)  
  17.     {  
  18.     }  
  19.   
  20.     void addStrongRef(const void/*id*/) { }  
  21.     void removeStrongRef(const void/*id*/) { }  
  22.     void addWeakRef(const void/*id*/) { }  
  23.     void removeWeakRef(const void/*id*/) { }  
  24.     void printRefs() const { }  
  25.     void trackMe(boolbool) { }  
  26.   
  27. #else  
  28.     weakref_impl(RefBase* base)  
  29.         : mStrong(INITIAL_STRONG_VALUE)  
  30.         , mWeak(0)  
  31.         , mBase(base)  
  32.         , mFlags(0)  
  33.         , mStrongRefs(NULL)  
  34.         , mWeakRefs(NULL)  
  35.         , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)  
  36.         , mRetain(false)  
  37.     {  
  38.         //LOGI("NEW weakref_impl %p for RefBase %p", this, base);  
  39.     }  
  40.   
  41.     ~weakref_impl()  
  42.     {  
  43.         LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!");  
  44.         LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!");  
  45.     }  
  46.   
  47.     void addStrongRef(const void* id)  
  48.     {  
  49.         addRef(&mStrongRefs, id, mStrong);  
  50.     }  
  51.   
  52.     void removeStrongRef(const void* id)  
  53.     {  
  54.         if (!mRetain)  
  55.             removeRef(&mStrongRefs, id);  
  56.         else  
  57.             addRef(&mStrongRefs, id, -mStrong);  
  58.     }  
  59.   
  60.     void addWeakRef(const void* id)  
  61.     {  
  62.         addRef(&mWeakRefs, id, mWeak);  
  63.     }  
  64.     void removeWeakRef(const void* id)  
  65.     {  
  66.         if (!mRetain)  
  67.             removeRef(&mWeakRefs, id);  
  68.         else  
  69.             addRef(&mWeakRefs, id, -mWeak);  
  70.     }  
  71.   
  72.     void trackMe(bool track, bool retain)  
  73.     {  
  74.         mTrackEnabled = track;  
  75.         mRetain = retain;  
  76.     }  
  77.   
  78.     ......  
  79.   
  80. private:  
  81.     struct ref_entry  
  82.     {  
  83.         ref_entry* next;  
  84.         const void* id;  
  85. #if DEBUG_REFS_CALLSTACK_ENABLED  
  86.         CallStack stack;  
  87. #endif  
  88.         int32_t ref;  
  89.     };  
  90.   
  91.     void addRef(ref_entry** refs, const void* id, int32_t mRef)  
  92.     {  
  93.         if (mTrackEnabled) {  
  94.             AutoMutex _l(mMutex);  
  95.             ref_entry* ref = new ref_entry;  
  96.             // Reference count at the time of the snapshot, but before the  
  97.             // update.  Positive value means we increment, negative--we  
  98.             // decrement the reference count.  
  99.             ref->ref = mRef;  
  100.             ref->id = id;  
  101. #if DEBUG_REFS_CALLSTACK_ENABLED  
  102.             ref->stack.update(2);  
  103. #endif  
  104.   
  105.             ref->next = *refs;  
  106.             *refs = ref;  
  107.         }  
  108.     }  
  109.   
  110.     void removeRef(ref_entry** refs, const void* id)  
  111.     {  
  112.         if (mTrackEnabled) {  
  113.             AutoMutex _l(mMutex);  
  114.   
  115.             ref_entry* ref = *refs;  
  116.             while (ref != NULL) {  
  117.                 if (ref->id == id) {  
  118.                     *refs = ref->next;  
  119.                     delete ref;  
  120.                     return;  
  121.                 }  
  122.   
  123.                 refs = &ref->next;  
  124.                 ref = *refs;  
  125.             }  
  126.   
  127.             LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",  
  128.                 id, mBase, this);  
  129.         }  
  130.     }  
  131.   
  132.     ......  
  133.   
  134.     Mutex mMutex;  
  135.     ref_entry* mStrongRefs;  
  136.     ref_entry* mWeakRefs;  
  137.   
  138.     bool mTrackEnabled;  
  139.     // Collect stack traces on addref and removeref, instead of deleting the stack references  
  140.     // on removeref that match the address ones.  
  141.     bool mRetain;  
  142.   
  143.     ......  
  144. #endif  
  145. };  
        这个类看起来实现得很复杂,其实不然,这个类的实现可以分成两部分:

[cpp] view plaincopy
  1. #if !DEBUG_REFS  
  2.   
  3. ......  
  4.   
  5. #else  
        编译指令之间的这部分源代码是Release版本的源代码,它的成员函数都是空实现;

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

[cpp] view plaincopy
  1. struct ref_entry  
  2. {  
  3.     ref_entry* next;  
  4.     const void* id;  
  5. #if DEBUG_REFS_CALLSTACK_ENABLED  
  6.     CallStack stack;  
  7. #endif  
  8.     int32_t ref;  
  9. };  
        这个结构体也是为了方便调试而使用的,我们可以不关注这部分用于调试的代码。

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

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

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

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


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

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

[cpp] view plaincopy
  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文件中:

[cpp] view plaincopy
  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类的构造函数中创建的:

[cpp] view plaincopy
  1. RefBase::RefBase()  
  2.     : mRefs(new weakref_impl(this))  
  3. {  
  4. //    LOGV("Creating refs %p with RefBase %p\n", mRefs, this);  
  5. }  
        在这个incStrong函数中,主要做了三件事情:

        一是增加弱引用计数:

[cpp] view plaincopy
  1. refs->addWeakRef(id);  
  2. refs->incWeak(id);  
        二是增加强引用计数:
[cpp] view plaincopy
  1. refs->addStrongRef(id);  
  2. const int32_t c = android_atomic_inc(&refs->mStrong);  
        三是如果发现是首次调用这个对象的incStrong函数,就会调用一个这个对象的onFirstRef函数,让对象有机会在对象被首次引用时做一些处理逻辑:
[cpp] view plaincopy
  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的,它的值为:

[cpp] view plaincopy
  1. #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函数:

[cpp] view plaincopy
  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. }  
       增加弱引用计数是下面语句执行的:
[cpp] view plaincopy
  1. 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。

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

[cpp] view plaincopy
  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文件中:

[cpp] view plaincopy
  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的操作是下面语句:
[cpp] view plaincopy
  1. const int32_t c = android_atomic_dec(&refs->mStrong);  
        如果发现减1前,此对象的强引用计数为1,就说明从此以后,就再没有地方引用这个目标对象了,这时候,就要看看是否要delete这个目标对象了:

[cpp] view plaincopy
  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函数:

[cpp] view plaincopy
  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的操作是下面语句:

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

[cpp] view plaincopy
  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. }  
        如果目标对象的生命周期是不受弱引用计数控制的,就执行下面语句:

[cpp] view plaincopy
  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的析构函数里面,的确是会做这件事情:

[cpp] view plaincopy
  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掉了。

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

[cpp] view plaincopy
  1. impl->mBase->onLastWeakRef(id);  
  2. if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {  
  3.     delete impl->mBase;  
  4. }  
        理论上说,如果目标对象的生命周期是受弱引用计数控制的,那么当强引用计数和弱引用计数都为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文件中:

[cpp] view plaincopy
  1. template <typename T>  
  2. class wp  
  3. {  
  4. public:  
  5.     typedef typename RefBase::weakref_type weakref_type;  
  6.   
  7.     inline wp() : m_ptr(0) { }  
  8.   
  9.     wp(T* other);  
  10.     wp(const wp<T>& other);  
  11.     wp(const sp<T>& other);  
  12.     template<typename U> wp(U* other);  
  13.     template<typename U> wp(const sp<U>& other);  
  14.     template<typename U> wp(const wp<U>& other);  
  15.   
  16.     ~wp();  
  17.   
  18.     // Assignment  
  19.   
  20.     wp& operator = (T* other);  
  21.     wp& operator = (const wp<T>& other);  
  22.     wp& operator = (const sp<T>& other);  
  23.   
  24.     template<typename U> wp& operator = (U* other);  
  25.     template<typename U> wp& operator = (const wp<U>& other);  
  26.     template<typename U> wp& operator = (const sp<U>& other);  
  27.   
  28.     void set_object_and_refs(T* other, weakref_type* refs);  
  29.   
  30.     // promotion to sp  
  31.   
  32.     sp<T> promote() const;  
  33.   
  34.     // Reset  
  35.   
  36.     void clear();  
  37.   
  38.     // Accessors  
  39.   
  40.     inline  weakref_type* get_refs() const { return m_refs; }  
  41.   
  42.     inline  T* unsafe_get() const { return m_ptr; }  
  43.   
  44.     // Operators  
  45.   
  46.     COMPARE_WEAK(==)  
  47.         COMPARE_WEAK(!=)  
  48.         COMPARE_WEAK(>)  
  49.         COMPARE_WEAK(<)  
  50.         COMPARE_WEAK(<=)  
  51.         COMPARE_WEAK(>=)  
  52.   
  53.         inline bool operator == (const wp<T>& o) const {  
  54.             return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);  
  55.     }  
  56.     template<typename U>  
  57.     inline bool operator == (const wp<U>& o) const {  
  58.         return m_ptr == o.m_ptr;  
  59.     }  
  60.   
  61.     inline bool operator > (const wp<T>& o) const {  
  62.         return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);  
  63.     }  
  64.     template<typename U>  
  65.     inline bool operator > (const wp<U>& o) const {  
  66.         return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);  
  67.     }  
  68.   
  69.     inline bool operator < (const wp<T>& o) const {  
  70.         return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);  
  71.     }  
  72.     template<typename U>  
  73.     inline bool operator < (const wp<U>& o) const {  
  74.         return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);  
  75.     }  
  76.     inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }  
  77.     template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }  
  78.     inline bool operator <= (const wp<T>& o) const { return !operator > (o); }  
  79.     template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }  
  80.     inline bool operator >= (const wp<T>& o) const { return !operator < (o); }  
  81.     template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }  
  82.   
  83. private:  
  84.     template<typename Y> friend class sp;  
  85.     template<typename Y> friend class wp;  
  86.   
  87.     T*              m_ptr;  
  88.     weakref_type*   m_refs;  
  89. };  
        与强指针类相比,它们都有一个成员变量m_ptr指向目标对象,但是弱指针还有一个额外的成员变量m_refs,它的类型是weakref_type指针,下面我们分析弱指针的构造函数时再看看它是如果初始化的。这里我们需要关注的仍然是弱指针的构造函数和析构函数。

        先来看构造函数:

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

[cpp] view plaincopy
  1. RefBase::weakref_type* RefBase::createWeak(const void* id) const  
  2. {  
  3.     mRefs->incWeak(id);  
  4.     return mRefs;  
  5. }  
        这里的成员变量mRefs的类型为weakref_impl指针,weakref_impl类的incWeak函数我们在前面已经看过了,它的作用就是增加对象的弱引用计数。函数最后返回mRefs,于是,弱指针对象的成员变量m_refs就指向目标对象的weakref_impl对象了。

        再来看析构函数:

[cpp] view plaincopy
  1. template<typename T>  
  2. wp<T>::~wp()  
  3. {  
  4.     if (m_ptr) m_refs->decWeak(this);  
  5. }  
        这里,弱指针在析构的时候,与强指针析构不一样,它直接就调用目标对象的weakref_impl对象的decWeak函数来减少弱引用计数了,当弱引用计数为0的时候,就会根据在目标对象的标志位(0、OBJECT_LIFETIME_WEAK或者OBJECT_LIFETIME_FOREVER)来决定是否要delete目标对象,前面我们已经介绍过了,这里就不再介绍了。

        分析到这里,弱指针还没介绍完,它最重要的特性我们还没有分析到。前面我们说过,弱指针的最大特点是它不能直接操作目标对象,这是怎么样做到的呢?秘密就在于弱指针类没有重载*和->操作符号,而强指针重载了这两个操作符号。但是,如果我们要操作目标对象,应该怎么办呢,这就要把弱指针升级为强指针了:

[cpp] view plaincopy
  1. template<typename T>  
  2. sp<T> wp<T>::promote() const  
  3. {  
  4.     return sp<T>(m_ptr, m_refs);  
  5. }  
        升级的方式就使用成员变量m_ptr和m_refs来构造一个强指针sp,这里的m_ptr为指目标对象的一个指针,而m_refs则是指向目标对象里面的weakref_impl对象。

        我们再来看看这个强指针的构造过程:

[cpp] view plaincopy
  1. template<typename T>  
  2. sp<T>::sp(T* p, weakref_type* refs)  
  3.     : m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)  
  4. {  
  5. }  
        主要就是初始化指向目标对象的成员变量m_ptr了,如果目标对象还存在,这个m_ptr就指向目标对象,如果目标对象已经不存在,m_ptr就为NULL,升级成功与否就要看refs->attemptIncStrong函数的返回结果了:
[cpp] view plaincopy
  1. bool RefBase::weakref_type::attemptIncStrong(const void* id)  
  2. {  
  3.     incWeak(id);  
  4.   
  5.     weakref_impl* const impl = static_cast<weakref_impl*>(this);  
  6.   
  7.     int32_t curCount = impl->mStrong;  
  8.     LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",  
  9.         this);  
  10.     while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {  
  11.         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {  
  12.             break;  
  13.         }  
  14.         curCount = impl->mStrong;  
  15.     }  
  16.   
  17.     if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {  
  18.         bool allow;  
  19.         if (curCount == INITIAL_STRONG_VALUE) {  
  20.             // Attempting to acquire first strong reference...  this is allowed  
  21.             // if the object does NOT have a longer lifetime (meaning the  
  22.             // implementation doesn't need to see this), or if the implementation  
  23.             // allows it to happen.  
  24.             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK  
  25.                 || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);  
  26.         } else {  
  27.             // Attempting to revive the object...  this is allowed  
  28.             // if the object DOES have a longer lifetime (so we can safely  
  29.             // call the object with only a weak ref) and the implementation  
  30.             // allows it to happen.  
  31.             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK  
  32.                 && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);  
  33.         }  
  34.         if (!allow) {  
  35.             decWeak(id);  
  36.             return false;  
  37.         }  
  38.         curCount = android_atomic_inc(&impl->mStrong);  
  39.   
  40.         // If the strong reference count has already been incremented by  
  41.         // someone else, the implementor of onIncStrongAttempted() is holding  
  42.         // an unneeded reference.  So call onLastStrongRef() here to remove it.  
  43.         // (No, this is not pretty.)  Note that we MUST NOT do this if we  
  44.         // are in fact acquiring the first reference.  
  45.         if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {  
  46.             impl->mBase->onLastStrongRef(id);  
  47.         }  
  48.     }  
  49.   
  50.     impl->addWeakRef(id);  
  51.     impl->addStrongRef(id);  
  52.   
  53. #if PRINT_REFS  
  54.     LOGD("attemptIncStrong of %p from %p: cnt=%d\n"this, id, curCount);  
  55. #endif  
  56.   
  57.     if (curCount == INITIAL_STRONG_VALUE) {  
  58.         android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);  
  59.         impl->mBase->onFirstRef();  
  60.     }  
  61.   
  62.     return true;  
  63. }  

        这个函数的作用是试图增加目标对象的强引用计数,但是有可能会失败,失败的原因可能是因为目标对象已经被delete掉了,或者是其它的原因,下面会分析到。前面我们在讨论强指针的时候说到,增加目标对象的强引用计数的同时,也会增加目标对象的弱引用计数,因此,函数在开始的地方首先就是调用incWeak函数来先增加目标对象的引用计数,如果后面试图增加目标对象的强引用计数失败时,会调用decWeak函数来回滚前面的incWeak操作。

        这里试图增加目标对象的强引用计数时,分两种情况讨论,一种情况是此时目标对象正在被其它强指针引用,即它的强引用计数大于0,并且不等于INITIAL_STRONG_VALUE,另一种情况是此时目标对象没有被任何强指针引用,即它的强引用计数小于等于0,或者等于INITIAL_STRONG_VALUE。

        第一种情况比较简单,因为这时候说明目标对象一定存在,因此,是可以将这个弱指针提升为强指针的,在这种情况下,只要简单地增加目标对象的强引用计数值就行了:

[cpp] view plaincopy
  1.    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {  
  2. if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {  
  3.     break;  
  4. }  
  5. curCount = impl->mStrong;  
  6.    }  
        当我们在这里对目标对象的强引用计数执行加1操作时,要保证原子性,因为其它地方也有可能正在对这个目标对象的强引用计数执行加1的操作,前面我们一般是调用android_atomic_inc函数来完成,但是这里是通过调用android_atomic_cmpxchg函数来完成,android_atomic_cmpxchg函数是体系结构相关的函数,在提供了一些特殊的指令的体系结构上,调用android_atomic_cmpxchg函数来执行加1操作的效率会比调用android_atomic_inc函数更高一些。函数android_atomic_cmpxchg是在system/core/include/cutils/atomic.h文件中定义的一个宏:

[cpp] view plaincopy
  1. int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue,  
  2.         volatile int32_t* addr);  
  3.   
  4. #define android_atomic_cmpxchg android_atomic_release_cas  
        它实际执行的函数是android_atomic_release_cas,这个函数的工作原理大概是这样的:如果它发现*addr == oldvalue,就会执行*addr = newvalue的操作,然后返回0,否则什么也不做,返回1。在我们讨论的这个场景中,oldvalue等于curCount,而newvalue等于curCount + 1,于是,在*addr == oldvalue的条件下,就相当于是对目标对象的强引用计数值增加了1。什么情况下*addr != oldvalue呢?在调用android_atomic_release_cas函数之前,oldvalue和值就是从地址addr读出来的,如果在执行android_atomic_release_cas函数的时候,有其它地方也对地址addr进行操作,那么就会有可能出现*addr != oldvalue的情况,这时候就说明其它地方也在操作目标对象的强引用计数了,因此,这里就不能执行增加目标对象的强引用计数的操作了,它必须要等到其它地方操作完目标对象的强引用计数之后再重新执行,这就是为什么要通过一个while循环来执行了。

        第二种情况比较复杂一点,因为这时候目标对象可能还存在,也可能不存了,这要根据实际情况来判断。如果此时目标对象的强引用计数值等于INITIAL_STRONG_VALUE,说明此目标对象还从未被强指针引用过,这时候弱指针能够被提升为强指针的条件就为:

[cpp] view plaincopy
  1. allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK  
  2.     || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);  

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

[cpp] view plaincopy
  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的时候,是否允计将弱指针提升为强指针。下面这个代码段就是执行上面所说的逻辑:

[cpp] view plaincopy
  1. allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK  
  2.     && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);  
       继续往下看:

[cpp] view plaincopy
  1. if (!allow) {  
  2.     decWeak(id);  
  3.     return false;  
  4. }  
  5. curCount = android_atomic_inc(&impl->mStrong);  
        如果allow值为false,那么就说明不允计把这个弱指针提升为强指针,因此就返回false了,在返回之前,要先调用decWeak函数来减少目标对象的弱引用计数,因为函数的开头不管三七二十一,首先就调用了incWeak来增加目标对象的弱引用计数值。

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

[cpp] view plaincopy
  1. if (curCount == INITIAL_STRONG_VALUE) {  
  2.     android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);  
  3.     impl->mBase->onFirstRef();  
  4. }  
        这个逻辑我们在前面分析强指针时已经分析过了,这里不再详述。

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

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

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

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

[cpp] view plaincopy
  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的内容如下:

[plain] view plaincopy
  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命令对工程进行编译:
[plain] view plaincopy
  1. USER-NAME@MACHINE-NAME:~/Android$ mmm ./external/weightpointer  
        编译之后,就可以打包了:

[plain] view plaincopy
  1. USER-NAME@MACHINE-NAME:~/Android$ make snod  
        最后得到可执行程序weightpointer就位于设备上的/system/bin/目录下。启动模拟器,通过adb shell命令进入到模拟器终端,进入到/system/bin/目录,执行weightpointer可执行程序,验证程序是否按照我们设计的逻辑运行:
[plain] view plaincopy
  1. USER-NAME@MACHINE-NAME:~/Android$ adb shell  
  2. root@android:/ # cd system/bin/          
  3. root@android:/system/bin # ./weightpointer    
        执行TestStrongClass函数的输出为:

[plain] view plaincopy
  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函数的输出为:

[plain] view plaincopy
  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函数的输出来:

[plain] view plaincopy
  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函数的输出来:

[plain] view plaincopy
  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系统的智能指针(轻量级指针、强指针和弱指针)的实现原理就分析完成了,它实现得很小巧但是很精致,希望读者可以通过实际操作细细体会一下。

21
0
查看评论
19楼 zzb_boy 2012-08-18 23:10发表 [回复]
罗兄,下面这段话让人有点走火入魔:
这里的成员变量mRefs的类型为weakref_impl指针,weakref_impl类的incWeak函数我们在前面已经看过了,它的作用就是增加对象的弱引用计数。函数最后返回mRefs,于是,弱指针对象的成员变量m_refs就指向目标对象的weakref_impl对象了。

这个“目标对象”,根据上下文的理解,读者一般会认为是泛型T的对象。但是你又说是weakref_impl对象。期待你的书面世,我认为你不管是文风还是技术解析,都是典范,现在CSDN上写android文章的一些所谓的大牛,写技术文章跟记流水帐一样,很不好。我希望你在你的新书当中加入一章,写写你的研究方法,学习方法,授人以渔。
Re: Luoshengyang 2012-08-19 00:03发表 [回复]
回复zzb_boy:目标对象T是从RefBase类继承下来的,而RefBase类有一个成员变量mRefs,指向一个weakref_impl对象。
弱指针类wp也有一个成员变量m_refs,从wp类的构造函数可以知道,它指向的就是目标对象T的成员变量mRefs所指向的那个weakref_impl对象。
不知道你是不是指“目标对象的weakref_impl对象”这句话?如果是的话,可能是表述的不是太准确,不过上面的理解是没有问题的。
至于你提到的学习方法嘛,貌似大家都比较有兴趣,以后我考虑可以整理一下,加再个现场操作的视频,可能就会更好一些。不过由于新书已经定型了,书里就不会包含有这些东西了。大家可以关注一下我的博客,这里会持续地有新的东西放出来。
多谢你的建议。
18楼 huangzhenyu1983 2012-07-18 12:44发表 [回复]
你好,博主。
看完这章节后有点疑惑,请教一下:
在main_mediaserver.cpp的main函数中的
为什么第一行代码要写成 
sp<ProcessState> proc(ProcessState::self());
而不直接写
ProcessState::self()?
是否是因为ProcessState::self这个函数中虽然gProcess是个智能指针,但是
if (gProcess == NULL) gProcess = new ProcessState;
这行代码并没有起到对引用数加1的功能,因此在main中需要用proc这个智能指针起到这样一个作用?那ProcessState这个对象又是在什么时候销毁的呢?

另外智能指针在初始化的时候指向一个对象,然后又在其他地方把这个智能指针指向了另一个对象,那是否先前那个对象永远不能被销毁了(因为初始的时候引用数加1了,但智能指针指向另一个对象时,先前那个对象却没有被-1)?

还有一个情况是,智能指针和普通指针混合着用,比如和一个对象既有智能指针指向它又有普通指针指向它,那是否通过普通指针进行操作的时候有可能这个已经被销毁了,而引起问题?
Re: Luoshengyang 2012-07-18 21:27发表 [回复]
回复huangzhenyu1983:1. 直接用ProcessState::self()也是可以的,不过如果需要多次引用ProcessState::self()的话,用一个独立的变量proc来指向它会更方便一些,至少可以少敲一些字母。这纯粹是使用习惯问题。
2. 当把一个裸指针赋值给一个智能指针的时候,这个裸指针所指向的对象的引用计数就会被增加1,这是智能指针的属性,否则就不能称为“智能”了。
3. 智能指针是一个对象,当它被析构的时候,就会自动减少它所引用的对象的引用计数。当被引用的对象的引用计数等于0的时候,就会被销毁。
4. 当一个智能指针从一个对象指向另一个对象的时候,前一个对象的引用计数会自动被减少1。这也是智能指针的属笥,否则也不能称为“智能”了。
5. 如果一个对象既被智能指针引用,又被裸指针引用,那么就需要由开发人员来保证这个对象的生命周期。根本就不应该这样使用。
17楼 yd2005zxq 2012-07-07 12:20发表 [回复]
受教了,非常不错,非常感谢楼主的分享!
16楼 lulinlin2010 2012-05-09 22:55发表 [回复]
刚看完第三段,有个小小的问题,照楼主所说的,假设A引用了B,B又引用了A,那么谁是父对象,谁是子对象呢?
Re: Luoshengyang 2012-05-10 00:26发表 [回复]
回复lulinlin2010:取决于A和B的业务关系,不同的业务可能不一样
15楼 edmond999 2012-03-29 14:38发表 [回复]
搞得很复杂!
14楼 fdasf 2011-11-02 18:01发表 [回复]
先谢谢LZ的详细分析。对于sp、wp相互的关系,我基本明白了,但对于它们的用处还是不大明白。比如什么时候用sp,什么时候用wp,我还是不清楚。如果我全部用sp,会有什么问题?还请LZ能解释一下。
Re: Luoshengyang 2011-11-02 22:09发表 [回复]
回复fdasf:文章中的第三段提到它们的用处了。这里再举一个例子,例如,你有一个ObjectMgr类,专门负责管理系统中的对象Obj的生命周期,创建和销毁等,而类A通过从ObjectMgr中获得对象Obj的引用来使用它们,但是类A无权干涉对象Obj的生命周期。这时候,如果类A在内部保存了对象Obj的引用,而此时ObjectMgr由于某些原因,需要销毁对象Obj,那么这个对象在类A中的引用就失效了。如果类A还是继续通过内部的引用而使用对象Obj,那肯定就会出问题,但是如果类A在内部保存的是对象Obj的弱引用,那么就不会有问题,因为当类A要使用Obj的时候,必须要把它内部的弱引用提升为强引用之后才能使用,这时候对象Obj已经不存在,提升为强引用就肯定会失败。
Re: fdasf 2011-11-03 16:12发表 [回复]
回复Luoshengyang:你说的这个意思我明白,但还是不清楚两者使用的时机。就针对你说的这个例子,那么我是不是可以认为,所有的地方都使用wp比较安全?如果不是这样,那么什么时候我们可以直接使用sp?
Re: Luoshengyang 2011-11-03 21:33发表 [回复]
回复fdasf:如果都用wp,那么和都用sp没有区别,关键是这样做的话,那么只要是获得了这个对象的引用的地方,都有权干涉对象的生命周期了。这个使用场景的前提是有一个专门的地方来负责对象的生命周期,其它地方只能在这个对象存在的时候就可以用,不存在的时候就不可以使用。
13楼 movie0125 2011-10-27 16:44发表 [回复]
看得脑袋晕晕的
12楼 AndroidBluetooth 2011-10-07 20:53发表 [回复]
文章分析的比较透彻,辛苦了!
11楼 yang_hui1986527 2011-09-29 12:35发表 [回复]
技术神贴~
感谢分享。
10楼 zxj382411196 2011-09-27 17:59发表 [回复]
感谢楼主分享,看了下,还是有好多不懂的。下去细细研究下!
9楼 xiguayipian 2011-09-27 09:39发表 [回复]
谢谢分享。不过在我们跨平台开发中还是倾向于用boost的智能指针。
Re: Luoshengyang 2011-09-27 10:11发表 [回复]
回复xiguayipian:跨平台的确是个问题,用第三方的库来屏蔽平台特性是个好方法,可能Google也正是考虑到Android系统是个开放的平台,面向的是众多的移动设备厂商,所以才决定用Java语言来开发Android的APP的吧。
Re: yx4521wdj 2011-09-27 15:37发表 [回复]
回复Luoshengyang:老罗,看了你的文章,写得确实很好,从Android的内核编译开始,到与硬件的连接……我的QQ:1514008185,您方便的话加我一下好吗?我有些问题想向您请教!
8楼 PinkFloyd 2011-09-26 12:49发表 [回复]
师弟文章很好
Re: Luoshengyang 2011-09-26 13:12发表 [回复]
回复PinkFloyd:柯师兄,好啊:)
7楼 wormsun 2011-09-25 16:53发表 [回复]
非常精彩。
感觉android中的sp、wp都可以弱化,sp可以所化为wp,而wp可以进一步弱化为普通指针,就是由于这个弱化功能,导致了巨复杂的实现,楼主能不能说明一下弱化到底有什么作用??

关于弱指针在chrome中也有非常精彩的实现,可以参考http://www.oschina.net/code/explore/chromium.r67069/o3d/core/cross/weak_ptr.h
Re: Luoshengyang 2011-09-25 16:59发表 [回复]
回复wormsun:文章中的第三段提到了:
......弱引用计数主要是用于垃圾收集(Garbage Collection)系统的,因为简单的引用计数技术不能处理系统中对象间循环引用的情况......
其实在Java的垃圾收集(Garbage Collection)系统里面,对象的引用计数除了强引用计数和弱引用计数,还有其它类型的计数存在,比这个复杂多了。
Re: wormsun 2011-09-25 22:01发表 [回复]
回复Luoshengyang:多谢回复。
6楼 victoryckl 2011-09-25 09:59发表 [回复]
受益匪浅,楼主辛苦了
5楼 dqxian 2011-09-23 19:43发表 [回复]
分析得不错,顶个
4楼 n5u99 2011-09-23 17:07发表 [回复]
越研究就越佩服Google那帮搞软件的。简直就是禽兽啊....
3楼 hugengzong 2011-09-23 14:12发表 [回复]
非常不错!楼主辛苦了
2楼 masky5310 2011-09-23 13:35发表 [回复] [引用] [举报]
不错,受教了
1楼 real_time 2011-09-23 13:28发表 [回复]
非常感谢,受益匪浅,再接再厉,哈哈~



http://blog.csdn.net/mfbao01/article/details/6255655

经常会在android的framework代码中发现sp<xxx>和wp<xxx>这样的指针,平时看的时候都把他当成一个普通的指针封装过掉了,这几天终于忍不住了,想深入了解一下。

相关的代码:

frameworks/base/include/utils/RefBase.h

frameworks/base/libs/utils/RefBase.cpp

sp和wp都是一个模板类,看一下sp类的定义:

 

view plaincopy to clipboardprint?
  1. template <typename T>   
  2. class sp   
  3. {   
  4. public:   
  5.     typedef typename RefBase::weakref_type weakref_type;   
  6.     inline sp() : m_ptr(0) { }   
  7.     sp(T* other);   
  8.     sp(const sp<T>& other);   
  9.     ~sp();   
  10.     ......   
  11. private:       
  12.     // Optimization for wp::promote().   
  13.     sp(T* p, weakref_type* refs);   
  14.        
  15.     T*              m_ptr;   
  16. };  

[cpp] view plaincopy
  1. template <typename T>  
  2. class sp  
  3. {  
  4. public:  
  5.     typedef typename RefBase::weakref_type weakref_type;  
  6.     inline sp() : m_ptr(0) { }  
  7.     sp(T* other);  
  8.     sp(const sp<T>& other);  
  9.     ~sp();  
  10.     ......  
  11. private:      
  12.     // Optimization for wp::promote().  
  13.     sp(T* p, weakref_type* refs);  
  14.       
  15.     T*              m_ptr;  
  16. };  

 

可以看到他确实封转了一个原生指针T* m_ptr. 再看一下其中一个构造函数和析构函数:

 

view plaincopy to clipboardprint?
  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()   
  10. {   
  11.     if (m_ptr) m_ptr->decStrong(this);   
  12. }  

[c-sharp] view plaincopy
  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()  
  10. {  
  11.     if (m_ptr) m_ptr->decStrong(this);  
  12. }  

 

咋一看好奇怪,因为在构造函数中调用了incStrong(),在析构函数中调用的decStrong(),显然是管理引用计数的函数,但是sp类的中并没有定义这两个函数,这两个函数是在RefBase类中定义的,由此可以得出结论:

要想使用sp<T>或者wp<T>, T必需要继承RefBase类才行

RefBase的静态关系如下:

 

 其中weakref_type是RefBase的内嵌类,weakref_impl则是weakref_type的子类,RefBase的大部分工作都是交由weakref_impl类来完成,通过RefBase的成员变量weakref_impl* const mRefs。查看其中一个sp的构造函数:

 

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

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

 

建立sp<xxx>的动态关系如下:

sp<T>

  --> RefBase : incStrong()

  -->weakref_impl : addStrongRef()

  -->android_atomic_inc(&refs->mStrong)

可见当一个普通指针变成一个sp指针后,将会由RefBase类维护该指针的引用计数,当引用为零时则自动释放该指针指向的内存:

 

view plaincopy to clipboardprint?
  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 (c == 1) {   
  7.         const_cast<RefBase*>(this)->onLastStrongRef(id);   
  8.         if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {   
  9.             delete this;    //引用为0,销毁   
  10.         }   
  11.     }   
  12.     refs->removeWeakRef(id);   
  13.     refs->decWeak(id);   
  14. }  

[c-sharp] view plaincopy
  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 (c == 1) {  
  7.         const_cast<RefBase*>(this)->onLastStrongRef(id);  
  8.         if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {  
  9.             delete this;    //引用为0,销毁  
  10.         }  
  11.     }  
  12.     refs->removeWeakRef(id);  
  13.     refs->decWeak(id);  
  14. }  

 

 wp<xxx>是怎么一回事?

wp其实是弱指针的意思,wp<T>类型不能直接对类型T进行操作,要想对T进行某种操作,必需把wp升级为sp指针,使用promote()来实现升级:

        wp<T> weakp= new T();

        sp<T> t = weakp.promote();

wp可能会在弱引用计数不为0的情况下被销毁,执行如下代码:

 

view plaincopy to clipboardprint?
  1. class WPTest : public RefBase {   
  2. public:   
  3.     WPTest(){   
  4.         LOGD("WPTest constructor");   
  5.     }   
  6.     virtual ~WPTest() {   
  7.         LOGD("WPTest destructor");   
  8.     }   
  9.   
  10.     virtual void onFirstRef() {   
  11.         LOGD("first weak ptr ref callback");   
  12.     }   
  13.   
  14.     virtual void onLastStrongRef(const void* id) {   
  15.         LOGD("last strong ptr ref callback");   
  16.     }   
  17.   
  18.     virtual void onLastWeakRef(const void* id) {   
  19.         LOGD("last weak ptr ref callback");   
  20.     }   
  21. };   
  22.   
  23.   
  24. int main()   
  25. {   
  26.     WPTest *T = new WPTest();   
  27.     {   
  28.         wp<WPTest> weakp(T);   
  29.   
  30.         {   
  31.             LOGD("promote to strong ptr.../n");   
  32.   
  33.             sp<WPTest> strongp = weakp.promote();   
  34.   
  35.             LOGD("strong ptr's lifetime is just about to finish .../n");   
  36.         }   
  37.   
  38.         LOGD("weak ptr's lifetime is just about to finish .../n");   
  39.     }   
  40.   
  41.     LOGD("weak ptr is out of scope./n");   
  42.   
  43.     return 0;   
  44. }  

[c-sharp] view plaincopy
  1. class WPTest : public RefBase {  
  2. public:  
  3.     WPTest(){  
  4.         LOGD("WPTest constructor");  
  5.     }  
  6.     virtual ~WPTest() {  
  7.         LOGD("WPTest destructor");  
  8.     }  
  9.   
  10.     virtual void onFirstRef() {  
  11.         LOGD("first weak ptr ref callback");  
  12.     }  
  13.   
  14.     virtual void onLastStrongRef(const void* id) {  
  15.         LOGD("last strong ptr ref callback");  
  16.     }  
  17.   
  18.     virtual void onLastWeakRef(const void* id) {  
  19.         LOGD("last weak ptr ref callback");  
  20.     }  
  21. };  
  22.   
  23.   
  24. int main()  
  25. {  
  26.     WPTest *T = new WPTest();  
  27.     {  
  28.         wp<WPTest> weakp(T);  
  29.   
  30.         {  
  31.             LOGD("promote to strong ptr.../n");  
  32.   
  33.             sp<WPTest> strongp = weakp.promote();  
  34.   
  35.             LOGD("strong ptr's lifetime is just about to finish .../n");  
  36.         }  
  37.   
  38.         LOGD("weak ptr's lifetime is just about to finish .../n");  
  39.     }  
  40.   
  41.     LOGD("weak ptr is out of scope./n");  
  42.   
  43.     return 0;  
  44. }  

 

程序打印的结果是:

D/sp-wp-sample(  225): WPTest constructor
D/sp-wp-sample(  225): promote to strong ptr...
D/sp-wp-sample(  225): first weak ptr ref callback
D/sp-wp-sample(  225): strong ptr's lifetime is just about to finish ...
D/sp-wp-sample(  225): last strong ptr ref callback
D/sp-wp-sample(  225): WPTest destructor
D/sp-wp-sample(  225): weak ptr's lifetime is just about to finish ...
D/sp-wp-sample(  225): weak ptr is out of scope.

由此可见虽然wp<WPTest >的生命周期还没有结束,但是因为升级为sp<WPTest >后,sp<WPTest >的强引用计数为0,导致WPTest 被销毁,当强引用为0而弱引用不为0时,WPTest 销毁时,基类RefBase的mRefs指向的weakref_impl类并没有释放,从而保证了弱引用可以继续起作用,这点可以从RefBase的析构函数中看出来:

 

view plaincopy to clipboardprint?
  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. }  

[c-sharp] view plaincopy
  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. }  

 

不过也可以改变这一行为,我们修改一下WPTest的构造函数:

 

view plaincopy to clipboardprint?
  1. WPTest(){   
  2.         LOGD("WPTest constructor");   
  3.         extendObjectLifetime(OBJECT_LIFETIME_WEAK);   
  4.     }  

[c-sharp] view plaincopy
  1. WPTest(){  
  2.         LOGD("WPTest constructor");  
  3.         extendObjectLifetime(OBJECT_LIFETIME_WEAK);  
  4.     }  

 

这时的打印结果是:

D/sp-wp-sample(  217): WPTest constructor
D/sp-wp-sample(  217): promote to strong ptr...
D/sp-wp-sample(  217): first weak ptr ref callbac
D/sp-wp-sample(  217): strong ptr's lifetime is j
D/sp-wp-sample(  217): last strong ptr ref callba
D/sp-wp-sample(  217): weak ptr's lifetime is j
D/sp-wp-sample(  217): last weak ptr ref callback
D/sp-wp-sample(  217): WPTest destructor
D/sp-wp-sample(  217): weak ptr is out of scope.

可以看出现在只有当强引用和弱引用的计数都为0时,WPTest对象才会被销毁。



http://blog.csdn.net/mfbao01/article/details/6255664

在Android的源代码中,经常会看到形如:sp<xxx>、wp<xxx>这样的类型定义,这其实是Android中的智能 指针。智能指针是C++中的一个概念,通过基于引用计数的方法,解决对象的自动释放的问题。在C++编程中,有两个很让人头痛的问题:一是忘记释放动态申 请的对象从而造成内存泄露;二是对象在一个地方释放后,又在别的地方被使用,从而引起内存访问错误。程序员往往需要花费很大精力进行精心设计,以避免这些 问题的出现。在使用智能指针后,动态申请的内存将会被自动释放(有点类似Java的垃圾回收),不需要再使用delete来释放对象,也不需要考虑一个对 象是否已经在其它地方被释放了,从而使程序编写工作减轻不少,而程序的稳定性大大提高。  Android的智能指针相关的源代码在下面两个文件中:
  frameworks/base/include/utils/RefBase.h
  frameworks/base/libs/utils/RefBase.cpp
  涉及的类以及类之间的关系如下图所示:


strong and weak pointer

  Android中定义了两种智能指针类型,一种是强指针sp(strong pointer),一种是弱指针(weak pointer)。其实称为强引用和弱引用更合适一些。强指针与一般意义的智能指针概念相同,通过引用计数来记录有多少使用者在使用一个对象,如果所有使 用者都放弃了对该对象的引用,则该对象将被自动销毁。
  弱指针也指向一个对象,但是弱指针仅仅记录该对象的地址,不能通过弱指针来访问该对象,也就是说不能通过弱智真来调用对象的成员函数或访问对象的成员变 量。要想访问弱指针所指向的对象,需首先将弱指针升级为强指针(通过wp类所提供的promote()方法)。弱指针所指向的对象是有可能在其它地方被销 毁的,如果对象已经被销毁,wp的promote()方法将返回空指针,这样就能避免出现地址访问错的情况。
  是不是很神奇?弱指针是怎么做到这一点的呢?其实说穿了一点也不复杂,原因就在于每一个可以被智能指针引用的对象都同时被附加了另外一个 weakref_impl类型的对象,这个对象中负责记录对象的强指针引用计数和弱指针引用计数。这个对象是智能指针的实现内部使用的,智能指针的使用者 看不到这个对象。弱指针操作的就是这个对象,只有当强引用计数和弱引用计数都为0时,这个对象才会被销毁。
  说了这么多原理,下面该看看到底智能指针该怎么使用了。假设现在有一个类MyClass,如果要使用智能指针来引用这个类的对象,那么这个类需满足下列两个前提条件:
  (1) 这个类是基类RefBase的子类或间接子类;
  (2) 这个类必须定义虚构造函数,即它的构造函数需要这样定义:
  virtual ~MyClass();
  满足了上述条件的类就可以定义智能指针了,定义方法和普通指针类似。比如普通指针是这样定义:
  MyClass* p_obj;
  智能指针是这样定义:
  sp<MyClass> p_obj;
  注意不要定义成 sp<MyClass>* p_obj。初学者容易犯这种错误,这样实际上相当于定义了一个指针的指针。尽管在语法上没有问题,但是最好永远不要使用这样的定义。
  定义了一个智能指针的变量,就可以象普通指针那样使用它,包括赋值、访问对象成员、作为函数的返回值、作为函数的参数等。比如:
  p_obj = new MyClass(); // 注意不要写成 p_obj = new sp<MyClass>
  sp<MyClass> p_obj2 = p_obj;
  p_obj->func();
  p_obj = create_obj();
  some_func(p_obj);
  注意不要试图delete一个智能指针,即 delete p_obj。不要担心对象的销毁问题,智能指针的最大作用就是自动销毁不再使用的对象。不需要再使用一个对象后,直接将指针赋值为NULL即可:
  p_obj = NULL;
  上面说的都是强指针,弱指针的定义方法和强指针类似,但是不能通过弱指针来访问对象的成员。下面是弱指针的示例:
  wp<MyClass> wp_obj = new MyClass();
  p_obj = wp_obj.promote(); // 升级为强指针。不过这里要用.而不是->,真是有负其指针之名啊
  wp_obj = NULL;
  智能指针用起来是很方便,在一般情况下最好使用智能指针来代替普通指针。但是需要知道一个智能指针其实是一个对象,而不是一个真正的指针,因此其运行效率是远远比不上普通指针的。所以在对运行效率敏感的地方,最好还是不要使用智能指针为好。





http://hi.baidu.com/donghaozheng/item/a605d993735602bdcc80e5e4

在android 中可以广泛看到的template<typename T> class Sp 句柄类实际上是android 为实现垃圾回收机制的智能指针。智能指针是c++ 中的一个概念,因为c++ 本身不具备垃圾回收机制,而且指针也不具备构造函数和析构函数,所以为了实现内存( 动态存储区) 的安全回收,必须对指针进行一层封装,而这个封装就是智能指针,其实说白了,智能指针就是具备指针功能同时提供安全内存回收的一个类。当然,智能指针的功能还不只这些,想了解更多大家可以去研究下~

智能指针有很多实现方式,android 中的sp 句柄类实际上就是google 实现的一种强引用的智能指针。我没有仔细看android sp 的实现方式,但其基本原理 是固定的,现在我们从一个相对简单的例子来看智能指针的实现:

首先看一个最简单的对指针的封装:

Template <typename T>

class SmartPtr{

public:

SmartPtr(T *p = 0):ptr(p){}

~SmartPtr(){delete ptr ;}

private:

T *ptr ;

};

通过上面的封装,我们就可以用下面的方式来使用SmartPtr 而不需要担心内存泄露的问题:

SmartPtr<int> pointer(new int) ;

*(pointer.ptr) = 10 ;

为了方便使用,我们可以对操作符进行重载,让智能指针的操作更像是指针:

T &operator*(){return *ptr}

T* operator->(){return ptr}

经过上面的重载,我们就可以像使用真正的指针一样而不需要去解决 内存泄露问题。

因为智能指针封装了指针,所以必须为其实现拷贝构造函数和“=”操作符重载。因为如果不提供这两个函数,当上面的智能指针进行赋值的时候必然会使指针指向同一个区域,一旦析构的话会导致同一个指针被delete 两次。

在这里,拷贝构造函数的实现是有技巧 的,使用拷贝构造函数创建一个新的只能指针时,并不建立新的对象,而是让新的智能指针指向同一个对象,实际上就是常说的浅复制。但是这样的话就会导致多个指针指向同一块内存区域,当调用析构函数的时候如何来保证同一块内存区域只会被delete 一次呢,这里实现的方法有很多,最常用的是引数控制。即在智能指针中加入一个计数器,每次增加一个对内存区域的强引用,则计数器加一,当计数器为0 时,这个对象就可以被删除了, 这个计数器采用动态分配跟指针分开存储, 因为这个计数器是多个智能指针需要共享的:

Template <typename T>

class SmartPtr{

public:

SmartPtr(T *p = 0):ptr(p){count = new int(1) ;}// 第一次创建的时候,引数肯定是1

SmartPtr(const SmartPtr & rhs):ptr(rhs.ptr),count(rhs.count){++*rhs.count ;}

T &operator*(){return *ptr}

T* operator->(){return ptr}

SmartPtr &operator=(const SmartPtr & rhs){

if(ptr == rhs.ptr)

return *this ;

if(--*count == 0){

    delete ptr ;

    delete count ;

    }

    ++*rhs.count ;

    count = rhs.count ;

    ptr = rhs.ptr ;

}

~SmartPtr(){

if(--*count==0)

delete ptr ;

delete count ;

}

private:

T *ptr ;

int *count ;

};

这样,一个智能指针就基本成形了,当然这只是最简单的智能指针,商业库提供的智能指针都提供非常强大的功能,如果能仔细研究透了android 在这方面的实现,应该在c++ 内存控制方面很有长进~~暂时还没有时间,还要顺着camera 往下看,有牛人懂的话email 多指教哈~~

出了智能指针sp 外,android 里面还出现了wp 这个指针类,实际上他是一个弱引用类型的指针类,弱引用是在.net 以及java 中经常用到的,弱引用是一个对象引用的持有者,使用弱引用后可以维持对对象的引用,但是不会阻止其被垃圾回收。如果一个对象只有弱引用了,那它就成为被垃圾回收的候选对象,就像没有剩余的引用一样,而且一旦对象被删除,所有的弱引用也会被清楚。弱引用适合那些数据 成员特别多,而且重新创建又相对容易的类,也就是俗称的胖子类,建立弱引用可以引用对象,但也不阻止其被垃圾回收,在内存的使用方面取得一定的平衡。

在android 中wp 类里面的promote 函数实际上就是将一个弱引用升级为一个强引用。不管是sp 还是wp ,实际上都是android 利用现有的c++ 特性来解决内存使用和回收的一种手段。





http://www.360doc.com/content/11/0410/10/3700464_108552116.shtml

研究Android的时候,经常会遇到sp、wp的东西,网上一搜,原来是android封装了c++中对象回收机制。
说明:
1. 如果一个类想使用智能指针,那么必须满足下面两个条件:
    a. 该类是虚基类RefBase的子类或间接子类
    b. 该类必须定义虚构造函数。如virtual ~MyClass();

 
2. 本文以类BBinder来进行说明,其余类使用sp或wp的情况类似
3. 代码路径:frameworks/base/libs/utils/RefBase.cpp
       frameworks/base/include/utils/RefBase.h

一、calss BBinder类说明
      class RefBase
      class IBinder
 class BpBinder   class BBinder
 class BBinder : public IBinder
 {
 ...
 protected:
     virtual             ~BBinder();
 ...
 }
 class IBinder : public virtual RefBase
 {
 ...
 protected:
     inline virtual      ~IBinder() { }
 ...
 }
 由上,可以看出BBinder和IBinder都是以public的方式继承于虚基类RefBase的。

二、sp wp对象的建立过程
 解析:sp<BBinder>  BB_ptr(new BBinder);
 这是一条定义sp指针BB_ptr的语句,他只想的对象是一个BBinder对象。
 如图所示。
 


 1》首先看一下new BBinder时都做了什么,特别是和该机制相关的初始化。
   c++中创建一个对象时,需要调用去构造函数,对于继承类,则是先调用其父类的构造函数,然后才会调用本身的
   构造函数。这里new一个BBinder对象时,顺序调用了:
    RefBase::RefBase() : mRefs(new weakref_impl(this)) {}
    inline   IBinder() {}
    BBinder::BBinder() : mExtras(NULL){}
   主要关注的是RefBase的构造函数,
   可以看出他是通过new weakref_impl(this)的结果来初始化私有成员mRefs
   这里的this指向BBinder对象自身,class weakref_impl继承于类RefBase的内嵌类weakref_type,然后该类
   weakref_impl又被类RefBase引用。类weakref_impl的构造函数如下:
   weakref_impl(RefBase* base)
        : mStrong(INITIAL_STRONG_VALUE)    // 1 << 28
        , mWeak(0)
        , mBase(base)             // new BBinder指针
        , mFlags(0)
        , mStrongRefs(NULL)          // sp引用链表指针
        , mWeakRefs(NULL)           // wp引用链表指针
        , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT) // 1
        , mRetain(false) {}
   
 2》new BBinder返回的是BBinder对象的指针,如:sp<BBinder>  BB_ptr(0x????????);
   sp实际上是一个类模板,这条语句最终是要建立一个sp的实例化对象,叫模板类BB_ptr
   这里生成BB_ptr对象所调用的构造函数是:
   template<typename T>
   sp<T>::sp(T* other)
       : m_ptr(other)
   {
       if (other) other->incStrong(this);
   }
   BB_ptr对象的私有指针指向刚刚前面生成的BBinder对象。
   接着调用函数incStrong(),该函数是RefBase类的成员函数,在子类中没有被重载,所以这里
   other->incStrong(this)的调用实际上是调用基类成员函数incStrong(this),这个this值是指向sp对象
   BB_ptr的指针。现在转去查看该成员函数的实现。
   
   void RefBase::incStrong(const void* id) const
   {
       weakref_impl* const refs = mRefs;
       /* 取得BBinder对象基类中的私有只读指针mRefs */
       refs->addWeakRef(id);
       /* 调用weakref_impl类定义时实现的成员函数addWeakRef, 见下注释1*/
       refs->incWeak(id);
       /* 调用weakref_impl类的基类weakref_type成员函数incWeak, 见下注释2*/
       
       refs->addStrongRef(id);
       // 调用weakref_impl类定义时实现的成员函数addStrongRef, 见下注释1
       const int32_t c = Android_atomic_inc(&refs->mStrong); 
     /* 该函数实际将refs->mStrong值加1,也就是增加强引用计数值。但是返回值为refs->mStrong-1 */
       LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
   #if PRINT_REFS
       LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
   #endif
       if (c != INITIAL_STRONG_VALUE)  {
           return;
       }
     /* c = INITIAL_STRONG_VALUE, 第一个强引用产生的时候才会出现这个情况 */
       Android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
     /* 返回值为INITIAL_STRONG_VALUE,refs->mStrong值变成1 */
       const_cast<RefBase*>(this)->onFirstRef();
   }
   
/************************注释1********************************/
void addWeakRef(const void* id)
{
    addRef(&mWeakRefs, id, mWeak);
}
void addStrongRef(const void* id)
{
    addRef(&mStrongRefs, id, mStrong);
}
addRef()是类weakref_impl的私有成员函数,addWeakRef()函数引用的是public成员变量,而addRef()函数可以操作私有数据。

    struct ref_entry
    {
        ref_entry* next;
        const void* id;
        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;
            ref->ref = mRef;
            ref->id = id;
            
            ref->next = *refs;
            *refs = ref;
   /*
   新出现的ref_entry结构体加入到链表头上,如果有n个sp指针指向同一个目标对象
   那么这里就有n个ref_entry结构体加入到这个单链表中,该结构体记录着如下数据
   1. id域记录着对应的sp强指针类对象的this值
   2. ref域记录的是当前sp强指针类对象是第几个引用目标对象的指针
   3. next域指向下一个指向目标对象的sp强指针对应的ref_entry结构体
   
   类RefBase的嵌套类weakref_type的子类的私有数据mRefs的私有二级指针成员mWeakRefs指向的是
   最后一个sp强指针对应的ref_entry结构体指针。

   总结一下:
   一个目标对象,可能被n个sp强指针指向,那么就存在n个class sp对象,同时每一个sp
   对象在目标对象的虚基类对象的成员类mRefs的私有二级指针成员mWeakRefs登记了一个
   ref_entry结构体,这些ref_entry结构体的地址都是由该链表管理,每一个
   ref_entry结构体和哪一个sp对象对应,也由该链表管理。同时链接数就是该链表节点的
   个数
   */
        }
    }
/************************注释1********************************/

/************************注释2********************************/
void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    // 强制类型转换,将基类指针转换成子类指针
    impl->addWeakRef(id); 
    // 调用类weakref_impl成员函数addWeakRef(),产生一个ref_entry结构体挂载mWeakRefs链表上
    const int32_t c = Android_atomic_inc(&impl->mWeak);
  /* impl->mWeak加1,表示已存在一个weak引用。但返回值c为操作前的结果 */
    LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
/************************注释2********************************/

 3》上面是定义一个sp指针,下面看看定义一个wp指针式如何实现的。
     wp<BBinder>  BB_wp_ptr(BB_ptr);
    下面是wp类对应上面定义类型的构造函数
   template<typename T>
   wp<T>::wp(const sp<T>& other)
       : m_ptr(other.m_ptr)
   {
       if (m_ptr) {
           m_refs = m_ptr->createWeak(this);
       }
   }
   this指针是指向wp对象的。createWeak()函数是RefBase类的成员函数。
   RefBase::weakref_type* RefBase::createWeak(const void* id) const
   {
       mRefs->incWeak(id);
       return mRefs;
   }
   mRefs指向的是第二步骤中产生的weakref_impl对象,调用基类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);
     /* impl->mWeak有加1,但返回值为操作前的结果 */
       LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
   }
   


三、sp、wp释放过程 
  sp<BBinder> BB_SP_ptr(BB_ptr);
  实际上BB_SP_ptr和前面的BB_ptr一样,指向的是同一个BBinder对象。另外需要注意的时,调用sp构造函数:
  template<typename T>
  sp<T>::sp(const sp<T>& other)
      : m_ptr(other.m_ptr)
  {
      if (m_ptr) m_ptr->incStrong(this);
  }
  同样是需要调用BBinder对象的incStrong()函数,使用weakref_impl对象来管理新添加进来的强引用,同时增加一个
  ref_entry结构体到weakref_impl对象的mStrongRefs,增加2个ref_entry结构体到weakref_impl对象的mWeakRefs。
  如上图所示。
  
  现在来看看释放sp、wp指针的情况。
  delete BB_SP_ptr;
  将会调用如下形式的sp析构函数:
  template<typename T>
  sp<T>::~sp()
  {
      if (m_ptr) m_ptr->decStrong(this);
  }
  m_ptr指向的是前面生成的BBinder对象,调用其基类函数decStrong(this),this值是指向BB_SP_ptr对象。
  
  void RefBase::decStrong(const void* id) const
  {
      weakref_impl* const refs = mRefs;
      refs->removeStrongRef(id); // 注释3,移除mStrongRefs链表中和该sp对应的ref_entry结构体
      const int32_t c = Android_atomic_dec(&refs->mStrong);
    /* 强引用计数减1, 但返回的是操作之前的引用计数值 */
      LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
      if (c == 1) {
       /*  c == 1说明刚刚removeStrongRef之前,整个系统中只存在一个sp对象引用目标对象,现在的情况就是
          系统中没有任何强指针对象来引用目标对象了,此时目标对象就会被删除释放
        */
          const_cast<RefBase*>(this)->onLastStrongRef(id);
          if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
              delete this; // mFlags =0 ,条件成立,删除目标对象,这里就会删除前面new出来的BBinder对象
          }
      }// 如果此时还有其他指向该目标对象的sp指针存在的话,就不会删除目标对象
      
      refs->removeWeakRef(id);
      refs->decWeak(id);
      /* 删除新建目标对象sp指针时在mWeakRefs链表上增加的两个ref_entry结构体 */
  }
  /*********************************注释3*********************************/
  void removeStrongRef(const void* id)
    {
        if (!mRetain) // mRetain 初始化成 flase
            removeRef(&mStrongRefs, id); 
            /* 删除mStrongRefs链表中对应id的ref_entry一项 */
      /* 也就是取消了该sp对象和目标对象的联系 */
        else
            addRef(&mStrongRefs, id, -mStrong);
    }
  
  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;
            }
        }
    }
  /*********************************注释3*********************************/
  
  delete BB_wp_ptr;
  这是删除目标对象的一个wp指针,会调用wp的析构函数:
  template<typename T>
  wp<T>::~wp()
  {
      if (m_ptr) m_refs->decWeak(this);
  }
  调用weakref_type类的decWeak()函数,如下:
  void RefBase::weakref_type::decWeak(const void* id)
  {
      weakref_impl* const impl = static_cast<weakref_impl*>(this);
      impl->removeWeakRef(id);// 移除weakref_impl对象mWeakRefs链表中对应id的ref_entry结构体
      const int32_t c = Android_atomic_dec(&impl->mWeak);// 引用计数减1
      LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
      if (c != 1) return; // c == 1, 说明这是系统中存在的指向目标对象的最后一个wp指针
      
      if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
          if (impl->mStrong == INITIAL_STRONG_VALUE)
              delete impl->mBase;
              // delete impl; 是不是应该加上这么一句,防止用户新建了wp后,不用,马上又删除的情况呢?
        /* 当目标对象的最后一个wp被析构时,如果目标对象还没有建立任何一个sp,那么目标对象被删除 */
          else {
              delete impl;
        /* 当目标对象的最后一个wp被析构时,但此时和目标对象相关的sp全部被析构,那么impl->mStrong = 0
            在最后一个sp被析构的时候,目标对象也被释放,所以此时只需要释放weakref_impl对象即可
        */
          }
      } else {
          impl->mBase->onLastWeakRef(id);
          if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
              delete impl->mBase;
          }
      }
  }

四、wp升级为sp的过程
  wp的定义包含了:sp<T> promote() const;
  template<typename T>
  sp<T> wp<T>::promote() const
  {
      return sp<T>(m_ptr, m_refs);
  }
  wp,sp互为友元类,这里promote就是以友元身份调用了sp<Binder>类的构造函数: sp(T* p, weakref_type* refs);
  template<typename T>
  sp<T>::sp(T* p, weakref_type* refs)
      : m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)
  {
  }
  这里如果升级成功,那么将会产生一个sp对象指向目标对象,原来的wp仍然存在。
  如果升级不成功,返回NULL
  看看关键函数refs->attemptIncStrong(this)

  bool RefBase::weakref_type::attemptIncStrong(const void* id)
  {
      incWeak(id);
      
      weakref_impl* const impl = static_cast<weakref_impl*>(this);
      
      int32_t curCount = impl->mStrong;
      LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
                 this);
      while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
          if (Android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
              break;
          }
          curCount = impl->mStrong;
      }// 系统中还有其他sp指向目标对象的情况
      
      if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
          bool allow;
          if (curCount == INITIAL_STRONG_VALUE) {
          // 发现该目标对象还没有一个sp对象与之相关联的话,那么将会新建一个对目标对象的强引用
              allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
                    || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
          } else {
          /*
       发现系统中原来指向目标对象的sp全部被释放,最后一次sp释放也将目标对象释放了
      */
              allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
                    && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
          }
          if (!allow) {
              decWeak(id); // 目标对象已经不存在了,释放前面incWeak(id)产生的ref_entry结构体
              return false; 
          }
          curCount = Android_atomic_inc(&impl->mStrong);
  
          if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
              impl->mBase->onLastStrongRef(id);
          }
      }
      // 走完生成一个sp的必要过程,和前面介绍的是一样
      impl->addWeakRef(id);
      impl->addStrongRef(id);
  
      if (curCount == INITIAL_STRONG_VALUE) {
          Android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
          impl->mBase->onFirstRef();
      }
      
      return true; // 返回true
  }
  
 

五、总结:
  1. weakref_impl对象会随着目标对象的生成而产生,但不一定会随着目标对象的释放而释放。例如:如果目标对象被
    1个sp引用,但是同时被2个wp引用,那么在sp被删除的时候,删除了目标对象,但没有删除weakref_impl对象,
    只有在最后一个wp释放时,weakref_impl对象会被释放。
  2. 一个目标对象被多个sp指针引用,没有wp引用的情况下。释放这些sp的时候,delete会调用sp析构函数,
    然后调用RefBase类的成员函数decStrong(), 最后一个sp被释放时,weakref_impl对象数据成员mStrong会
    从1减到0(注意mStrong的初始化值为1<<28, 从这个值可以判断出该目标对象有没有被sp指针引用过),
    同时释放目标对象。
  3. 一个目标对象被多个wp指针引用,没有sp引用的情况下。delete这些wp的时候,会调用wp的析构函数,该函数会
    调用函数decWeak()。当删除最后一个wp的时候,代码中只是删除了目标对象,而没有释放weakref_impl对象,
    暂时没发现在哪里释放了它。
  4. 一个目标对象既有sp,又有wp来引用。如果sp先被删除光,那么最后一个sp删除的时候会释放掉目标对象,那么此时
    mStrong = 0。在后续最后一个wp的释放过程中,在decWeak()函数中就会判断出impl->mStrong != 
    INITIAL_STRONG_VALUE,而释放掉剩下的weakref_impl对象了。如果先所以的wp删除光,此时mWeak还等于剩余的sp
    的个数,所以此时的释放情况,同第2小点的说明。
  5. 从wp定义来看,wp是不能直接操作对象的,必须先升级为sp才行。这个升级的过程是依靠函数promote()来完成的。
    升级成功,返回新生成的sp对象指针,升级失败,返回NULL。需要注意的是,如果目标对象之前有过sp指向,但后来
    将所有的sp释放完之后,此时目标对象是不存在的,那么此时用户还想将指向该目标对象的wp升级为sp的话,
    此时就返回NULL。那么这个时候我们应该delete这些剩下的wp。


原创粉丝点击