当前位置: 首页 > news >正文

网站开发建设方案书安康教育平台

网站开发建设方案书,安康教育平台,安阳做网站推广,专做运动装的网站Android系统的运行时库层代码是用C来编写的#xff0c;用C 来写代码最容易出错的地方就是指针了#xff0c;一旦使用不当#xff0c;轻则造成内存泄漏#xff0c;重则造成系统崩溃。不过系统为我们提供了智能指针#xff0c;避免出现上述问题#xff0c;本文将系统地分析… 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文件中 template class T class LightRefBase { public:inline 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_castconst T*(this);}}//! DEBUGGING ONLY: Get current strong ref count.inline int32_t getStrongCount() const {return mCount;}protected:inline ~LightRefBase() { }private:mutable 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 { public:typedef typename RefBase::weakref_type weakref_type;inline sp() : m_ptr(0) { }sp(T* other);sp(const spT other);templatetypename U sp(U* other);templatetypename U sp(const spU other);~sp();// Assignmentsp operator (T* other);sp operator (const spT other);templatetypename U sp operator (const spU other);templatetypename U sp operator (U* other);//! Special optimization for use by ProcessState (and nobody else).void force_set(T* other);// Resetvoid clear();// Accessorsinline T operator* () const { return *m_ptr; }inline T* operator- () const { return m_ptr; }inline T* get() const { return m_ptr; }// OperatorsCOMPARE()COMPARE(!)COMPARE()COMPARE()COMPARE()COMPARE()private:templatetypename Y friend class sp;templatetypename Y friend class wp;// Optimization for wp::promote().sp(T* p, weakref_type* refs);T* m_ptr; }; 这个类的内容比较多但是这里我们只关注它的成员变量m_ptr、构造函数和析构函数。不难看出成员变量m_ptr就是指向真正的对象了它是在构造函数里面初始化的。接下来我们就再看一下它的两个构造函数一个是普通构造函数一个拷贝构造函数 templatetypename T spT::sp(T* other): m_ptr(other) {if (other) other-incStrong(this); }templatetypename T spT::sp(const spT other): m_ptr(other.m_ptr) {if (m_ptr) m_ptr-incStrong(this); } 这两个构造函数都会首先初始化成员变量m_ptr然后再调用m_ptr的incStrong函数来增加对象的引用计数在我们这个场景中就是调用LightRefBase类的incStrong函数了。 最后看一下析构函数 templatetypename T spT::~sp() {if (m_ptr) m_ptr-decStrong(this); } 析构函数也很简单只是调用m_ptr的成员函数decStrong来减少对象的引用计数值这里就是调用LightRefBase类的decStrong函数了前面我们看到当这个引用计数减1后变成0时就会自动delete这个对象了。 轻量级智能指针的实现原理大概就是这样了比较简单下面我们再用一个例子来说明它的用法。 2. 轻量级指针的用法 我们在external目录下建立一个C工程目录lightpointer它里面有两个文件一个lightpointer.cpp文件另外一个是Android.mk文件。 源文件lightpointer.cpp的内容如下 #include stdio.h #include utils/RefBase.husing namespace android;class LightClass : public LightRefBaseLightClass { public:LightClass(){printf(Construct LightClass Object.);}virtual ~LightClass(){printf(Destory LightClass Object.);} };int main(int argc, char** argv) {LightClass* pLightClass new LightClass();spLightClass lpOut pLightClass;printf(Light Ref Count: %d.\n, pLightClass-getStrongCount());{spLightClass 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 : optional LOCAL_MODULE : lightpointer LOCAL_SRC_FILES : lightpointer.cpp LOCAL_SHARED_LIBRARIES : \libcutils \libutils include $(BUILD_EXECUTABLE) 最后我们参照如何单独编译Android源代码中的模块一文使用mmm命令对工程进行编译 USER-NAMEMACHINE-NAME:~/Android$ mmm ./external/lightpointer 编译之后就可以打包了 USER-NAMEMACHINE-NAME:~/Android$ make snod 最后得到可执行程序lightpointer就位于设备上的/system/bin/目录下。启动模拟器通过adb shell命令进入到模拟器终端进入到/system/bin/目录执行lightpointer可执行程序验证程序是否按照我们设计的逻辑运行 USER-NAMEMACHINE-NAME:~/Android$ adb shell rootandroid:/ # cd system/bin/ rootandroid:/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 { public:void incStrong(const void* id) const;void decStrong(const void* id) const;void forceIncStrong(const void* id) const;//! DEBUGGING ONLY: Get current strong ref count.int32_t getStrongCount() const;class 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) const;weakref_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);private:friend 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 { public:volatile int32_t mStrong;volatile int32_t mWeak;RefBase* const mBase;volatile int32_t mFlags;#if !DEBUG_REFSweakref_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) { }#elseweakref_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);elseaddRef(mStrongRefs, id, -mStrong);}void addWeakRef(const void* id){addRef(mWeakRefs, id, mWeak);}void removeWeakRef(const void* id){if (!mRetain)removeRef(mWeakRefs, id);elseaddRef(mWeakRefs, id, -mWeak);}void trackMe(bool track, bool retain){mTrackEnabled track;mRetain retain;}......private:struct ref_entry{ref_entry* next;const void* id; #if DEBUG_REFS_CALLSTACK_ENABLEDCallStack stack; #endifint32_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_ENABLEDref-stack.update(2); #endifref-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 doesnt 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_ENABLEDCallStack stack; #endifint32_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来指向它的宿主类RefBasemFlags是一个标志位它指示了维护对象引用计数所使用的策略后面我们将会分析到它的取值为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类了这里就不再把它的代码列出来了。我们来看看它的构造函数的实现 templatetypename T spT::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%d\n, this, id, c);#endif if (c ! INITIAL_STRONG_VALUE) { return; } android_atomic_add(-INITIAL_STRONG_VALUE, refs-mStrong); const_castRefBase*(this)-onFirstRef(); } 成员变量mRefs是在RefBase类的构造函数中创建的 在这个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_castRefBase*(this)-onFirstRef(); 这里的c返回的是refs-mStrong加1前的值如果发现等于INITIAL_STRONG_VALUE就说明这个对象的强引用计数是第一次被增加因此refs-mStrong就是初始化为INITIAL_STRONG_VALUE的它的值为 #define INITIAL_STRONG_VALUE (128) 这个值加1后等于128 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_castweakref_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这个问题他是这样回答的 Ah I see. Well the debug code may be broken, though I wouldnt 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 isnt working and need to do this to fix it. 既然他也不知道怎么回事我们也不必深究了知道有这么回事就行。 这里总结一下强指针类sp在其构造函数里面所做的事情就是分别为目标对象的强引用计数和弱引和计数增加了1。 再来看看强指针类的析构函数的实现 templatetypename T spT::~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_REFSLOGD(decStrong of %p from %p: cnt%d\n, this, id, c); #endifLOG_ASSERT(c 1, decStrong() called on %p too many times, refs);if (c 1) {const_castRefBase*(this)-onLastStrongRef(id);if ((refs-mFlagsOBJECT_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_castRefBase*(this)-onLastStrongRef(id);if ((refs-mFlagsOBJECT_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_castweakref_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-mFlagsOBJECT_LIFETIME_WEAK) ! OBJECT_LIFETIME_WEAK) {if (impl-mStrong INITIAL_STRONG_VALUE)delete impl-mBase;else { // LOGV(Freeing refs %p of old RefBase %p\n, this, impl-mBase);delete impl;}} else {impl-mBase-onLastWeakRef(id);if ((impl-mFlagsOBJECT_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-mFlagsOBJECT_LIFETIME_WEAK) ! OBJECT_LIFETIME_WEAK) {if (impl-mStrong INITIAL_STRONG_VALUE)delete impl-mBase;else { // LOGV(Freeing refs %p of old RefBase %p\n, this, impl-mBase);delete impl;} } else {impl-mBase-onLastWeakRef(id);if ((impl-mFlagsOBJECT_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 %p\n, 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 %p\n, mRefs, this);delete mRefs;} }但是不要忘记在这个场景下目标对象是前面的RefBase::decStrong函数delete掉的这时候目标对象就会被析构但是它的弱引用计数值尚未执行减1操作因此这里的mRefs-mWeak 0条件就不成立于是就不会delete这个weakref_impl对象因此就延迟到执行这里decWeak函数时再执行。 如果是后一种情景这里的impl-mStrong值就等于INITIAL_STRONG_VALUE了这时候由于没有地方会负责delete目标对象因此就需要把目标对象imp-mBasedelete掉了否则就会造成内存泄漏。在delete这个目标对象的时候就会执行RefBase类的析构函数这时候目标对象的弱引用计数等于0于是就会把weakref_impl对象也一起delete掉了。 回到外层的if语句中如果目标对象的生命周期是受弱引用计数控制的就执行下面语句 impl-mBase-onLastWeakRef(id); if ((impl-mFlagsOBJECT_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 { public:typedef typename RefBase::weakref_type weakref_type;inline wp() : m_ptr(0) { }wp(T* other);wp(const wpT other);wp(const spT other);templatetypename U wp(U* other);templatetypename U wp(const spU other);templatetypename U wp(const wpU other);~wp();// Assignmentwp operator (T* other);wp operator (const wpT other);wp operator (const spT other);templatetypename U wp operator (U* other);templatetypename U wp operator (const wpU other);templatetypename U wp operator (const spU other);void set_object_and_refs(T* other, weakref_type* refs);// promotion to spspT promote() const;// Resetvoid clear();// Accessorsinline weakref_type* get_refs() const { return m_refs; }inline T* unsafe_get() const { return m_ptr; }// OperatorsCOMPARE_WEAK()COMPARE_WEAK(!)COMPARE_WEAK()COMPARE_WEAK()COMPARE_WEAK()COMPARE_WEAK()inline bool operator (const wpT o) const {return (m_ptr o.m_ptr) (m_refs o.m_refs);}templatetypename Uinline bool operator (const wpU o) const {return m_ptr o.m_ptr;}inline bool operator (const wpT o) const {return (m_ptr o.m_ptr) ? (m_refs o.m_refs) : (m_ptr o.m_ptr);}templatetypename Uinline bool operator (const wpU o) const {return (m_ptr o.m_ptr) ? (m_refs o.m_refs) : (m_ptr o.m_ptr);}inline bool operator (const wpT o) const {return (m_ptr o.m_ptr) ? (m_refs o.m_refs) : (m_ptr o.m_ptr);}templatetypename Uinline bool operator (const wpU o) const {return (m_ptr o.m_ptr) ? (m_refs o.m_refs) : (m_ptr o.m_ptr);}inline bool operator ! (const wpT o) const { return m_refs ! o.m_refs; }templatetypename U inline bool operator ! (const wpU o) const { return !operator (o); }inline bool operator (const wpT o) const { return !operator (o); }templatetypename U inline bool operator (const wpU o) const { return !operator (o); }inline bool operator (const wpT o) const { return !operator (o); }templatetypename U inline bool operator (const wpU o) const { return !operator (o); }private:templatetypename Y friend class sp;templatetypename Y friend class wp;T* m_ptr;weakref_type* m_refs; }; 与强指针类相比它们都有一个成员变量m_ptr指向目标对象但是弱指针还有一个额外的成员变量m_refs它的类型是weakref_type指针下面我们分析弱指针的构造函数时再看看它是如果初始化的。这里我们需要关注的仍然是弱指针的构造函数和析构函数。 先来看构造函数 templatetypename T wpT::wp(T* other): m_ptr(other) {if (other) m_refs other-createWeak(this); } 这里的参数other一定是继承了RefBase类因此这里调用了RefBase类的createWeak函数它定义在frameworks/base/libs/utils/RefBase.cpp文件中 RefBase::weakref_type* RefBase::createWeak(const void* id) const {mRefs-incWeak(id);return mRefs; } 这里的成员变量mRefs的类型为weakref_impl指针weakref_impl类的incWeak函数我们在前面已经看过了它的作用就是增加对象的弱引用计数。函数最后返回mRefs于是弱指针对象的成员变量m_refs就指向目标对象的weakref_impl对象了。 再来看析构函数 templatetypename T wpT::~wp() {if (m_ptr) m_refs-decWeak(this); } 这里弱指针在析构的时候与强指针析构不一样它直接就调用目标对象的weakref_impl对象的decWeak函数来减少弱引用计数了当弱引用计数为0的时候就会根据在目标对象的标志位0、OBJECT_LIFETIME_WEAK或者OBJECT_LIFETIME_FOREVER来决定是否要delete目标对象前面我们已经介绍过了这里就不再介绍了。 分析到这里弱指针还没介绍完它最重要的特性我们还没有分析到。前面我们说过弱指针的最大特点是它不能直接操作目标对象这是怎么样做到的呢秘密就在于弱指针类没有重载*和-操作符号而强指针重载了这两个操作符号。但是如果我们要操作目标对象应该怎么办呢这就要把弱指针升级为强指针了 templatetypename T spT wpT::promote() const {return spT(m_ptr, m_refs); } 升级的方式就使用成员变量m_ptr和m_refs来构造一个强指针sp这里的m_ptr为指目标对象的一个指针而m_refs则是指向目标对象里面的weakref_impl对象。 我们再来看看这个强指针的构造过程 templatetypename T spT::sp(T* p, weakref_type* refs): m_ptr((p refs-attemptIncStrong(this)) ? p : 0) { } 主要就是初始化指向目标对象的成员变量m_ptr了如果目标对象还存在这个m_ptr就指向目标对象如果目标对象已经不存在m_ptr就为NULL升级成功与否就要看refs-attemptIncStrong函数的返回结果了 bool RefBase::weakref_type::attemptIncStrong(const void* id) {incWeak(id);weakref_impl* const impl static_castweakref_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, curCount1, impl-mStrong) 0) {break;}curCount impl-mStrong;}if (curCount 0 || curCount INITIAL_STRONG_VALUE) {bool allow;if (curCount INITIAL_STRONG_VALUE) {// Attempting to acquire first strong reference... this is allowed// if the object does NOT have a longer lifetime (meaning the// implementation doesnt need to see this), or if the implementation// allows it to happen.allow (impl-mFlagsOBJECT_LIFETIME_WEAK) ! OBJECT_LIFETIME_WEAK|| impl-mBase-onIncStrongAttempted(FIRST_INC_STRONG, id);} else {// Attempting to revive the object... this is allowed// if the object DOES have a longer lifetime (so we can safely// call the object with only a weak ref) and the implementation// allows it to happen.allow (impl-mFlagsOBJECT_LIFETIME_WEAK) OBJECT_LIFETIME_WEAK impl-mBase-onIncStrongAttempted(FIRST_INC_STRONG, id);}if (!allow) {decWeak(id);return false;}curCount android_atomic_inc(impl-mStrong);// If the strong reference count has already been incremented by// someone else, the implementor of onIncStrongAttempted() is holding// an unneeded reference. So call onLastStrongRef() here to remove it.// (No, this is not pretty.) Note that we MUST NOT do this if we// are in fact acquiring the first reference.if (curCount 0 curCount INITIAL_STRONG_VALUE) {impl-mBase-onLastStrongRef(id);}}impl-addWeakRef(id);impl-addStrongRef(id);#if PRINT_REFSLOGD(attemptIncStrong of %p from %p: cnt%d\n, this, id, curCount); #endifif (curCount INITIAL_STRONG_VALUE) {android_atomic_add(-INITIAL_STRONG_VALUE, impl-mStrong);impl-mBase-onFirstRef();}return true; } 这个函数的作用是试图增加目标对象的强引用计数但是有可能会失败失败的原因可能是因为目标对象已经被delete掉了或者是其它的原因下面会分析到。前面我们在讨论强指针的时候说到增加目标对象的强引用计数的同时也会增加目标对象的弱引用计数因此函数在开始的地方首先就是调用incWeak函数来先增加目标对象的引用计数如果后面试图增加目标对象的强引用计数失败时会调用decWeak函数来回滚前面的incWeak操作。 这里试图增加目标对象的强引用计数时分两种情况讨论一种情况是此时目标对象正在被其它强指针引用即它的强引用计数大于0并且不等于INITIAL_STRONG_VALUE另一种情况是此时目标对象没有被任何强指针引用即它的强引用计数小于等于0或者等于INITIAL_STRONG_VALUE。 第一种情况比较简单因为这时候说明目标对象一定存在因此是可以将这个弱指针提升为强指针的在这种情况下只要简单地增加目标对象的强引用计数值就行了 while (curCount 0 curCount ! INITIAL_STRONG_VALUE) { if (android_atomic_cmpxchg(curCount, curCount1, impl-mStrong) 0) {break; } curCount impl-mStrong; } 当我们在这里对目标对象的强引用计数执行加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文件中定义的一个宏 int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue,volatile int32_t* addr);#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说明此目标对象还从未被强指针引用过这时候弱指针能够被提升为强指针的条件就为 allow (impl-mFlagsOBJECT_LIFETIME_WEAK) ! OBJECT_LIFETIME_WEAK|| impl-mBase-onIncStrongAttempted(FIRST_INC_STRONG, id); 即如果目标对象的生命周期只受到强引用计数控制或者在目标对象的具体实现中总是允许这种情况发生。怎么理解呢如果目标对象的生命周期只受强引用计数控制它的标志位mFlags为0而这时目标对象又还未被强指针引用过它自然就不会被delete掉因此这时候可以判断出目标对象是存在的如果目标对象的生命周期受弱引用计数控制OBJECT_LIFETIME_WEAK这时候由于目标对象正在被弱指针引用因此弱引用计数一定不为0目标对象一定存在如果目标对象的生命周期不受引用计数控制BJECT_LIFETIME_FOREVER这时候目标对象也是下在被弱指针引用因此目标对象的所有者必须保证这个目标对象还没有被delete掉否则就会出问题了。在后面两种场景下因为目标对象的生命周期都是不受强引用计数控制的而现在又要把弱指针提升为强指针就需要进一步调用目标对象的onIncStrongAttempted来看看是否允许这种情况发生这又该怎么理解呢可以这样理解目标对象的设计者可能本身就不希望这个对象被强指针引用只能通过弱指针来引用它因此这里它就可以重载其父类的onIncStrongAttempted函数然后返回false这样就可以阻止弱指针都被提升为强指针。在RefBase类中其成员函数onIncStrongAttempted默认是返回true的 bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id) {return (flagsFIRST_INC_STRONG) ? true : false; } 如果此时目标对象的强引用计数值小于等于0那就说明该对象之前一定被强指针引用过这时候就必须保证目标对象是被弱引用计数控制的BJECT_LIFETIME_WEAK否则的话目标对象就已经被delete了。同样这里也要调用一下目标对象的onIncStrongAttempted成员函数来询问一下目标对象在强引用计数值小于等于0的时候是否允计将弱指针提升为强指针。下面这个代码段就是执行上面所说的逻辑 allow (impl-mFlagsOBJECT_LIFETIME_WEAK) OBJECT_LIFETIME_WEAK impl-mBase-onIncStrongAttempted(FIRST_INC_STRONG, id); 继续往下看 if (!allow) {decWeak(id);return false; } curCount android_atomic_inc(impl-mStrong); 如果allow值为false那么就说明不允计把这个弱指针提升为强指针因此就返回false了在返回之前要先调用decWeak函数来减少目标对象的弱引用计数因为函数的开头不管三七二十一首先就调用了incWeak来增加目标对象的弱引用计数值。 函数attemptIncStrong的主体逻辑大概就是这样了比较复杂读者要细细体会一下。函数的最后如果此弱指针是允计提升为强指针的并且此目标对象是第一次被强指针引用还需要调整一下目标对象的强引用计数值 if (curCount INITIAL_STRONG_VALUE) {android_atomic_add(-INITIAL_STRONG_VALUE, impl-mStrong);impl-mBase-onFirstRef(); } 这个逻辑我们在前面分析强指针时已经分析过了这里不再详述。 分析到这里弱指针就介绍完了。强指针和弱指针的关系比较密切同时它们也比较复杂下面我们再举一个例子来说明强指针和弱指针的用法同时也验证一下它们的实现原理。 5. 强指针和弱指针的用法 参考在Ubuntu上为Android系统内置C可执行程序测试Linux内核驱动程序一文我们在external目录下建立一个C工程目录weightpointer它里面有两个文件一个weightpointer.cpp文件另外一个是Android.mk文件。 源文件weightpointer.cpp的内容如下 #include stdio.h #include utils/RefBase.h#define INITIAL_STRONG_VALUE (128)using namespace android;class WeightClass : public RefBase { public:void printRefCount(){int32_t strong getStrongCount();weakref_type* ref getWeakRefs();printf(-----------------------\n);printf(Strong Ref Count: %d.\n, (strong INITIAL_STRONG_VALUE ? 0 : strong));printf(Weak Ref Count: %d.\n, ref-getWeakCount());printf(-----------------------\n);} };class StrongClass : public WeightClass { public:StrongClass(){printf(Construct StrongClass Object.\n);}virtual ~StrongClass(){printf(Destory StrongClass Object.\n);} };class WeakClass : public WeightClass { public:WeakClass(){extendObjectLifetime(OBJECT_LIFETIME_WEAK);printf(Construct WeakClass Object.\n);}virtual ~WeakClass(){printf(Destory WeakClass Object.\n);} };class ForeverClass : public WeightClass { public:ForeverClass(){extendObjectLifetime(OBJECT_LIFETIME_FOREVER);printf(Construct ForeverClass Object.\n);}virtual ~ForeverClass(){printf(Destory ForeverClass Object.\n);} };void TestStrongClass(StrongClass* pStrongClass) {wpStrongClass wpOut pStrongClass;pStrongClass-printRefCount();{spStrongClass spInner pStrongClass;pStrongClass-printRefCount();}spStrongClass spOut wpOut.promote();printf(spOut: %p.\n, spOut.get()); }void TestWeakClass(WeakClass* pWeakClass) {wpWeakClass wpOut pWeakClass;pWeakClass-printRefCount();{spWeakClass spInner pWeakClass;pWeakClass-printRefCount();}pWeakClass-printRefCount();spWeakClass spOut wpOut.promote();printf(spOut: %p.\n, spOut.get()); }void TestForeverClass(ForeverClass* pForeverClass) {wpForeverClass wpOut pForeverClass;pForeverClass-printRefCount();{spForeverClass spInner pForeverClass;pForeverClass-printRefCount();} }int main(int argc, char** argv) {printf(Test Strong Class: \n);StrongClass* pStrongClass new StrongClass();TestStrongClass(pStrongClass);printf(\nTest Weak Class: \n);WeakClass* pWeakClass new WeakClass();TestWeakClass(pWeakClass);printf(\nTest Froever Class: \n);ForeverClass* pForeverClass new ForeverClass();TestForeverClass(pForeverClass);pForeverClass-printRefCount();delete pForeverClass;return 0; } 首先定义了一个基类WeightClass继承于RefBase类它只有一个成员函数printRefCount作用是用来输出引用计数。接着分别定义了三个类StrongClass、WeakClass和ForeverClass其中实例化StrongClass类的得到的对象的标志位为默认值0实例化WeakClass类的得到的对象的标志位为OBJECT_LIFETIME_WEAK实例化ForeverClass类的得到的对象的标志位为OBJECT_LIFETIME_FOREVER后两者都是通过调用RefBase类的extendObjectLifetime成员函数来设置的。 在main函数里面分别实例化了这三个类的对象出来然后分别传给TestStrongClass函数、TestWeakClass函数和TestForeverClass函数来说明智能指针的用法我们主要是通过考察它们的强引用计数和弱引用计数来验证智能指针的实现原理。 编译脚本文件Android.mk的内容如下 LOCAL_PATH : $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS : optional LOCAL_MODULE : weightpointer LOCAL_SRC_FILES : weightpointer.cpp LOCAL_SHARED_LIBRARIES : \libcutils \libutils include $(BUILD_EXECUTABLE) 最后我们参照如何单独编译Android源代码中的模块一文使用mmm命令对工程进行编译 USER-NAMEMACHINE-NAME:~/Android$ mmm ./external/weightpointer 编译之后就可以打包了 USER-NAMEMACHINE-NAME:~/Android$ make snod 最后得到可执行程序weightpointer就位于设备上的/system/bin/目录下。启动模拟器通过adb shell命令进入到模拟器终端进入到/system/bin/目录执行weightpointer可执行程序验证程序是否按照我们设计的逻辑运行 USER-NAMEMACHINE-NAME:~/Android$ adb shell rootandroid:/ # cd system/bin/ rootandroid:/system/bin # ./weightpointer 执行TestStrongClass函数的输出为 Test Strong Class: Construct StrongClass Object. ----------------------- Strong Ref Count: 0. Weak Ref Count: 1. ----------------------- ----------------------- Strong Ref Count: 1. Weak Ref Count: 2. ----------------------- Destory StrongClass Object. 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函数的输出为 Test Weak Class: Construct WeakClass Object. ----------------------- Strong Ref Count: 0. Weak Ref Count: 1. ----------------------- ----------------------- Strong Ref Count: 1. Weak Ref Count: 2. ----------------------- ----------------------- Strong Ref Count: 0. Weak Ref Count: 1. ----------------------- spOut: 0xa528. Destory WeakClass Object. TestWeakClass函数和TestStrongClass函数的执行过程基本一样所不同的是当程序跳出大括号之后虽然这个WeakClass对象的强引用计数值已经为0但是由于它的生命周期同时受强引用计数和弱引用计数控制而这时它的弱引用计数值大于0因此这个WeakClass对象不会被delete掉这一点可以从后面试图把弱批针wpOut提升为强指针时得到的对象指针不为0得到验证。 执行TestForeverClass函数的输出来 Test Froever Class: Construct ForeverClass Object. ----------------------- Strong Ref Count: 0. Weak Ref Count: 1. ----------------------- ----------------------- Strong Ref Count: 1. Weak Ref Count: 2. ----------------------- 当执行完TestForeverClass函数返回到main函数的输出来 ----------------------- Strong Ref Count: 0. Weak Ref Count: 0. ----------------------- Destory ForeverClass Object. 这里我们可以看出虽然这个ForeverClass对象的强引用计数和弱引用计数值均为0了但是它不自动被delete掉虽然由我们手动地delete这个对象它才会被析构这是因为这个ForeverClass对象的生命周期是既不受强引用计数值控制也不会弱引用计数值控制。 这样从TestStrongClass、TestWeakClass和TestForeverClass这三个函数的输出就可以验证了我们上面对Android系统的强指针和弱指针的实现原理的分析。 6. 强弱指针的对比 通过类图可以发现强指针实现了 “.” “-” 操作符的重载因此sp 可以直接方位类成员而wp 却不能但是wp 可以转化为sp至此Android系统的智能指针轻量级指针、强指针和弱指针的实现原理就分析完成了它实现得很小巧但是很精致希望读者可以通过实际操作细细体会一下。 转载于:https://www.cnblogs.com/linhaostudy/p/9507896.html
http://www.zqtcl.cn/news/138958/

相关文章:

  • 深圳市门户网站建设哪家好微信小程序案例源码
  • 信息产业部icp备案中心网站asp网站制作教程
  • 品牌网站建设的意义建站公司联系电话
  • 网站建设 备案什么意思哪里有做效果图的网站
  • 教你免费申请个人网站html网站建设方案
  • 网站运营方案怎么写?在线制作手机网站
  • 微信html5模板网站哪个网站有手机
  • 网站知名度网站广东省备案系统
  • 柯桥区网站建设湖南人文科技学院
  • 建设一个网站需要哪些福田企业网站推广哪个好
  • 网站外链建设的15个小技巧中国农业建设中心网站
  • 交易平台网站怎么做wordpress 置顶 函数
  • 义乌市场官方网站jsp做就业网站
  • 推荐网站在线看兄弟们企业概况简介
  • 软装设计方案网站网站制作排名优化
  • 网站前端模板专业建站报价
  • 站长工具星空传媒怎么做游戏网站编辑
  • 大兴手机网站建设深圳小程序开发公司
  • c 大型网站开发案例电销系统线路
  • 鸿扬家装网站建设谈谈对seo的理解
  • 七米网站建设做网站也分内存大小的吗
  • 丝足网站的建设南宁关键词排名公司
  • 上饶商城网站建设亚马逊海外购官方网
  • 做网站代理商好赚吗高端品牌男鞋有哪些
  • 农产品网站建设及优化项目商务网站建设 视频
  • 北京兼职做网站建设百度app平台
  • 网站建设头部代码网站怎么做咨询
  • 网站运营 网站建设北京公司网站制作要多少钱
  • 郑州看妇科最好的医院是哪里南宁百度seo软件
  • 深圳市住房与建设局实名制网站手机网站打不开被拦截怎么办