ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
我们首先分析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; }; ~~~ 与LightRefBase类一样,RefBase类也提供了成员函数incStrong和decStrong来维护它所引用的对象的引用计数。不过,RefBase类与LightRefBase类不一样,它不是直接使用一个整数来维护对象的引用计数的,而是使用一个weakref_impl对象,即成员变量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_REFS weakref_impl(RefBase* base) : mStrong(INITIAL_STRONG_VALUE) , mWeak(0) , mBase(base) , mFlags(0) { } void addStrongRef(const void* /*id*/) { } void removeStrongRef(const void* /*id*/) { } void addWeakRef(const void* /*id*/) { } void removeWeakRef(const void* /*id*/) { } void printRefs() const { } void trackMe(bool, bool) { } #else ...... #endif }; ~~~ weakref_impl类继承了weakref_type类。weakref_type类定义在RefBase类的内部,它提供了成员函数incWeak、decWeak、attemptIncStrong和attemptIncWeak来维护对象的强引用计数和弱引用计数。weakref_type类只定义了引用计数维护接口,具体的实现是由weakref_impl类提供的。 weakref_impl类有两个成员变量mStrong和mWeak,分别用来描述对象的强引用计数和弱引用计数。同时,weakref_impl类的成员变量mBase指向了它所引用的对象的地址,而成员变量mFlags是一个标志值,用来描述对象的生命周期控制方式。weakref_impl类的成员变量mFlags的取值范围为0、OBJECT_LIFETIME_WEAK或者OBJECT_LIFETIME_FOREVER,其中,0表示对象的生命周期只受强引用计数影响;OBJECT_LIFETIME_WEAK表示对象的生命周期同时受强引用计数和弱引用计数影响;OBJECT_LIFETIME_FOREVER表示对象的生命周期完全不受强引用计数或者弱引用计数影响。 weakref_impl类的实现有调试和非调试两个版本,它们是通过宏DEBUG_REFS来区别的。如果定义了宏DEBUG_REFS,则weakref_impl类被编译成调试版本;否则被编译成非调试版本。weakref_impl类的调试版本只是用于调试它本身的实现,我们不关心,因此省略了这些代码。 下面我们就通过一个类图来总结RefBase、weakref_type和weakref_impl三个类的关系,如图3-1所示。 ![ RefBase、weakref_type和weakref_impl类的关系](https://box.kancloud.cn/4829f723f5b3f26efd053f5d9b0e5463_631x316.jpg =631x316) 从这个类图就可以看出,每一个RefBase对象都包含了一个weakref_impl对象,而后者继承了weakref_type类。在接下来的内容中,我们会进一步介绍这三个类的作用及其关系。 强指针的实现类为sp,在前面的3.1.1小节中,我们只分析了它的轻量级指针实现。在本节中,我们将分析sp类的强指针实现,主要是分析它的构造函数和析构函数的实现。 sp类的构造函数的实现如下所示。 **frameworks/base/include/utils/RefBase.h** ~~~ template<typename T> sp<T>::sp(T* other) : m_ptr(other) { if (other) other->incStrong(this); } ~~~ > 注意:模块参数T是一个继承了RefBase类的子类,因此,第5行实际上是调用了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_cast<RefBase*>(this)->onFirstRef(); } ~~~ RefBase类的成员变量mRefs是在构造函数中初始化的,如下所示。 **frameworks/base/libs/utils/RefBase.cpp** ~~~ RefBase::RefBase() : mRefs(new weakref_impl(this)) { // LOGV("Creating refs %p with RefBase %p\n", mRefs, this); } ~~~ 回到RefBase类的成员函数incStrong中,它主要做了三件事情:第一件事情是调用第5行代码来增加对象的弱引用计数;第二件事情是调用第8行代码来增加对象的强引用计数;第三件事情是如果发现对象是第一次被强指针引用,则第20行调用对象的成员函数onFirstRef来通知对象,它被强指针引用了,以便它可以执行一些业务相关逻辑。RefBase类的成员函数onFirstRef是一个空实现,如果子类想要处理这个事件,那么就必须要重写成员函数onFirstRef。 增加对象的弱引用计数是通过调用RefBase类的成员变量mRefs的成员函数incWeak来实现的。RefBase类的成员变量mRefs的类型为weakref_impl,它的成员函数incWeak是从父类weakref_type继承下来的,因此,它实际上是通过调用weakref_type类的成员函数incWeak来增加对象的弱引用计数的,如下所示。 **frameworks/base/libs/utils/RefBase.cpp** ~~~ void RefBase::weakref_type::incWeak(const void* id) { weakref_impl* const impl = static_cast<weakref_impl*>(this); impl->addWeakRef(id); const int32_t c = android_atomic_inc(&impl->mWeak); LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this); } ~~~ this指针指向的实际上是一个weakref_impl对象,因此,第3行将它转换为一个weakref_impl指针impl。有了这个impl指针之后,我们就可以访问它的成员变量mWeak了。第5行调用函数android_atomic_inc来增加它的成员变量mWeak的值,即增加对象的弱引用计数。第4行的函数调用是与调试相关的,我们忽略它的实现。 回到RefBase类的成员函数incStrong中,增加了对象的弱引用计数之后,接下来就调用函数android_atomic_inc来增加对象的强引用计数了,即增加RefBase类的引用计数对象mRefs的成员变量mStrong的值。函数android_atomic_inc的返回值是对象原来的强引用计数值,即加1前的值。在weakref_impl类的构造函数中,成员变量mStrong的值被初始化为INITIAL_STRONG_VALUE。INITIAL_STRONG_VALUE是一个宏,它的定义如下所示。 **frameworks/base/libs/utils/RefBase.cpp** ~~~ #define INITIAL_STRONG_VALUE (1<<28) ~~~ 从理论上说,当对象第一次被强指针引用时,它的强引用计数值应该等于1,但是我们看到,对象的强引用计数的初始值为INITIAL_STRONG_VALUE,它加1之后并不等于1,因此,RefBase类的成员函数incStrong需要将它调整为1,如第19行代码所示。 至此,强指针类sp的构造函数的实现就分析完了,它主要做的事情就是增加对象的强引用计数和弱引用计数。从这里就可以看出,虽然我们的目的是增加对象的强引用计数,但是同时也会增加对象的弱引用计数,即一个对象的弱引用计数一定是大于或者等于它的强引用计数的。 下面我们再来分析sp类的析构函数的实现,如下所示。 **frameworks/base/include/utils/RefBase.h** ~~~ template<typename T> sp<T>::~sp() { if (m_ptr) m_ptr->decStrong(this); } ~~~ 前面提到,sp类的成员变量m_ptr所指向的对象是继承了RefBase类的,因此,第4行实际上是调用了RefBase类的成员函数decStrong来减少对象的强引用计数,它的实现如下所示。 **frameworks/base/libs/utils/RefBase.cpp** ~~~ void RefBase::decStrong(const void* id) const { weakref_impl* const refs = mRefs; refs->removeStrongRef(id); const int32_t c = android_atomic_dec(&refs->mStrong); #if PRINT_REFS LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c); #endif LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs); if (c == 1) { const_cast<RefBase*>(this)->onLastStrongRef(id); if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { delete this; } } refs->removeWeakRef(id); refs->decWeak(id); } ~~~ 我们忽略第4行和第16行代码,因为它们在非调试版本中是空函数调用。sp类的析构函数执行的操作刚好与构造函数相反,它主要是减少对象的强引用计数和弱引用计数。 第5行代码通过调用函数android_atomic_dec来减少对象的强引用计数。与函数android_atomic_inc类似,函数android_atomic_dec的返回值是对象原来的强引用计数值,即减1前的值,保存在变量c中。如果变量c的值等于1,就说明此时再也没有强指针引用这个对象了,因此,第11行就调用该对象的成员函数onLastStrongRef来使得它可以执行一些业务相关的逻辑,同时也要考虑是否需要释放该对象。第12行检查对象的生命周期是否受弱引用计数控制,即RefBase类的成员变量mRefs的标志值mFlags的OBJECT_LIFETIME_WEAK位是否等于1。如果不等于1,就说明对象的生命周期不受弱引用计数影响,因此,第13行就会释放对象所占用的内存,这同时会导致RefBase类的析构函数被调用。 **frameworks/base/libs/utils/RefBase.cpp** ~~~ 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类的析构函数中,如果发现对象的弱引用计数值为0,那么就会把引用计数对象mRefs也一起释放。RefBase类的成员变量mRefs指向的是一个weakref_impl对象,它是在RefBase类的构造函数中创建的。现在既然它所属的RefBase对象已经不存在了,并且它所引用的对象的弱引用计数值也等于0,它也就不需要存在了。前面提到,一个对象的弱引用计数一定是大于等于它的强引用计数的,因此,当一个对象的强引用计数值为0时,它的弱引用计数值可能大于0。在对象的弱引用计数值大于0的情况下,我们只能将对应的RefBase对象释放掉,而不能将该RefBase对象内部的weakref_impl对象也释放掉,因为还有其他的弱指针通过该weakref_impl对象来引用实际的对象。只有当对象的弱引用计数值也为0 时,才可以将该weakref_impl对象也一起释放掉。 回到RefBase类的成员函数decStrong中,第17行代码执行减少对象的弱引用计数的操作。变量refs指向的是RefBase类内部的weakref_impl对象mRefs。weakref_impl类的成员函数decWeak是从父类weakref_type继承下来的,因此,接下来实际执行的是weakref_type类的成员函数decWeak,它的实现如下所示。 **frameworks/base/libs/utils/RefBase.cpp** ~~~ void RefBase::weakref_type::decWeak(const void* id) { weakref_impl* const impl = static_cast<weakref_impl*>(this); impl->removeWeakRef(id); const int32_t c = android_atomic_dec(&impl->mWeak); LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this); if (c != 1) return; if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { if (impl->mStrong == INITIAL_STRONG_VALUE) delete impl->mBase; else { // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase); delete impl; } } else { impl->mBase->onLastWeakRef(id); if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) { delete impl->mBase; } } } ~~~ 第4行的函数调用在非调试版本中是空函数调用,我们将它忽略。第5行调用android_atomic_dec函数来减少对象的弱引用计数,并且返回减少之前的值,保存在变量c中。如果c的值不等于1,那么就说明还有其他的弱指针在引用这个对象,因此,就不用进一步处理了;如果c的值等于1,那么就说明再也没有弱指针引用这个对象了,同时也说明没有强指针引用这个对象了,因为当对象的弱引用计数值等于0时,它的强引用计数值也一定等于0。在对象的弱引用计数值等于0时,我们就要考虑是否需要将该对象释放掉。这取决于对象的生命周期控制方式,以及该对象是否被强指针引用过。下面我们分为两种情况来考虑。 第一种情况是对象的生命周期只受强引用计数控制,即第9行的if语句为true。此时如果第10行的if语句也为true,即对象从来没有被强指针引用过,那么在该对象的弱引用计数值等于0时,第11行就需要将该对象释放掉;否则,这个对象以后就会得不到释放。当一个只受强引用计数控制的对象只被弱指针引用时,就会出现这种情况。如果对象的生命周期只受强引用计数控制,并且它也被强指针引用过,那么在该对象的弱引用计数值变为0时,该对象就已经在RefBase类的成员函数decStrong中被释放,因此,第14行只负责释放其内部的引用计数器对象weakref_impl。 第二种情况是对象的生命周期受弱引用计数控制,即第9行的if语句为false。第17行首先调用对象的成员函数onLastWeakRef来使得它可以执行一些业务相关的逻辑,同时也要考虑是否需要将该对象释放掉。第18行检查对象的生命周期是否完全不受强引用计数和弱引用计数控制,即RefBase类的成员变量mRefs的标志值mFlags的OBJECT_LIFETIME_FOREVER位是否等于1。如果不等于1,那么第19行就会释放对象所占用的内存。 从第二种情况就可以看出,当对象的生命周期控制标志值设置为OBJECT_LIFETIME_FOREVER时,即对象的生命周期完全不受强引用计数和弱引用计数控制时,Android系统所提供的智能指针就退化成一个普通的C++指针了,这时候开发人员就需要手动地释放那些不再使用了的对象所占用的内存。 至此,强指针的实现原理就分析完了。为了加深对它的理解,我们对对象的生命周期控制方式作一个小结。 (1)如果一个对象的生命周期控制标志值被设置为0,那么只要它的强引用计数值为0,系统就会自动释放这个对象。 (2)如果一个对象的生命周期控制标志值被设置为OBJECT_LIFETIME_WEAK,那么只有当它的强引用计数值和弱引用计数值都为0时,系统才会自动释放这个对象。 (3)如果一个对象的生命周期控制标志值被设置为OBJECT_LIFETIME_FOREVER,那么系统就 永远不会自动释放这个对象,它需要由开发人员来手动地释放。 接下来,我们继续分析弱指针的实现原理。