最近研究Android4.4源码,小结一下关于引用计数部分。跟书上讲的还有点不太一样,除了目录有变化外,代码有点变动,根据书中以及网上参考的一些资料,做个小的总结:
声明在system\core\include\utils目录下,实现在system\core\Libutils下。
为了在VS下编译测试,所以修改了一些东西:【不得不说模板调试还真是比较痛苦】
它的基类RefBase定义如下:
class RefBase { public: void incStrong(const void* id) const; void decStrong(const void* id) const; void forceIncStrong(const void* id) const; 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); bool attemptIncWeak(const void* id); int32_t getWeakCount() const; void printRefs() const; void trackMe(bool enable, bool retain); }; weakref_type* createWeak(const void* id) const; weakref_type* getWeakRefs() const; inline void printRefs() const { getWeakRefs()->printRefs(); } inline void trackMe(bool enable, bool retain) { getWeakRefs()->trackMe(enable, retain); } typedef RefBase basetype; protected: RefBase(); virtual ~RefBase(); //! Flags for extendObjectLifetime() enum { OBJECT_LIFETIME_STRONG = 0x0000, OBJECT_LIFETIME_WEAK = 0x0001, OBJECT_LIFETIME_MASK = 0x0001 }; 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 ReferenceMover; static void moveReferences(void* d, void const* s, size_t n, const ReferenceConverterBase& caster); private: friend class weakref_type; class weakref_impl; RefBase(const RefBase& o); RefBase& operator=(const RefBase& o); weakref_impl* const mRefs; };
RefBase中有一个内部类,weakref_type,里边主要是关于incWeak,decWeak操作等函数,这里边只有函数, 没有其他变量,主要是被用来继承使用的。事实上weakref_impl类就是从weakref_type继承而来的,注意代码中最后几行中,weakref_impl的声明,class weakref_impl,这种写法也是内部类一种,只不过定义的时候需要加上类的全名,如 class RefBase::weakref_impl : public RefBase::weakref_type。根据测试结果,其实内部类的this和外部类的this指向的地址,简单来说,外部类的this指向类的头地址,而内部类的this而是根据内部类对象的位置偏移而设定,也就是说,内部类的this地址其实指向外部类的一部分,而且使用class weakref_impl这种声明方式,定义只能使用指针,而不能是变量,我的猜想是,因为这个类在RefBase中只是一个声明,不知道具体内容,所以没法确定大小,只能定义指针了。
注意,默认构造函数是protected,复制构造函数被声明为private,也就是说,没法通过定义一个RefBase变量了,这样设计的目的就是被这个类只能被继承使用,即所谓的基类型。【忘了说了,RefBase中只有一个成员变量:weakref_impl* const mRefs】
类中的那几个虚函数是调试版本所用,发行版没有实现,
在内部类weakref_type中,第一个函数是:
RefBase* refBase() const;
返回值是RefBase的指针,它的实现如下:
RefBase* RefBase::weakref_type::refBase() const { return static_cast<const weakref_impl*>(this)->mBase; }
class RefBase::weakref_impl : public RefBase::weakref_type { public: volatile int32_t mStrong; volatile int32_t mWeak; RefBase* const mBase;//指向RefBase本身 volatile int32_t mFlags; weakref_impl(RefBase* base) : mStrong(INITIAL_STRONG_VALUE) , mWeak(0) , mBase(base) , mFlags(0) { } };
RefBase::RefBase() : mRefs(new weakref_impl(this)) { }
void RefBase::weakref_type::incWeak(const void* id) { weakref_impl* const impl = static_cast<weakref_impl*>(this); const int32_t c = android_atomic_inc(&impl->mWeak); } void RefBase::incStrong(const void* id) const { weakref_impl* const refs = mRefs; refs->incWeak(id); const int32_t c = android_atomic_inc(&refs->mStrong); if (c != INITIAL_STRONG_VALUE) { return; } android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); refs->mBase->onFirstRef();//自己测试时这种函数直接删掉 }
在图中可以看到,RefBase中只负责强引用的工作,所以它只有incStrong,decStrong,forceIncStrong等函数操作,而弱引用则需要通过weakref_type类型来操作,因此,weakref_type类型也仅仅只有incWeak,decWeak等操作,有个例外是attemptIncWeak和attempIncStrong函数操作,因为需要由弱生强,所以从弱引用到强引用需要特殊判断,大致的步骤在promote函数中,意思是,一个对象可能由弱引用控制,那么当弱引用为0时(此时必然强引用为0),可以delete掉,如果是强引用控制,那么只要强引用为0,无论弱引用多少,都可以delete掉,那么在使用的时候就需要判断对象到底还存在否,如果是永久性的,那么他的生命周期不受此限制,所以在提升的时候需要根据这些情况作出判断,因此,就多了这个关于强引用的函数。
最后说明一点,所有的操作均是对impl这个对象来操作的,无论是通过mRefs引用还是从type强制转换过来。
关于WP和SP
wp和sp分别是弱引用和强引用的模板类
sp定义在StrongPoint.h文件中(在之前的版本中,它是定义在RefBase这个文件中的)
声明如下:
template <typename T> class sp { public: inline sp() : m_ptr(0) { } sp(T* other); sp(const sp<T>& other); template<typename U> sp(U* other); template<typename U> sp(const sp<U>& other); ~sp(); // Assignment sp& operator = (T* other); sp& operator = (const sp<T>& other); template<typename U> sp& operator = (const sp<U>& other); template<typename U> sp& operator = (U* other); //! Special optimization for use by ProcessState (and nobody else). void force_set(T* other); // Reset void clear(); // Accessors inline T& operator* () const { return *m_ptr; } inline T* operator-> () const { return m_ptr; } inline T* get() const { return m_ptr; } // Operators COMPARE(==) COMPARE(!=) COMPARE(>) COMPARE(<) COMPARE(<=) COMPARE(>=) private: template<typename Y> friend class sp; template<typename Y> friend class wp; void set_pointer(T* ptr); T* m_ptr; };
拿SP的构造函数说一下:
template<typename T> sp<T>::sp(T* other) : m_ptr(other) { if (other) other->incStrong(this); } template<typename T> sp<T>::sp(const sp<T>& other) : m_ptr(other.m_ptr) { if (m_ptr) m_ptr->incStrong(this); } template<typename T> template<typename U> sp<T>::sp(U* other) : m_ptr(other) { if (other) ((T*)other)->incStrong(this); } template<typename T> template<typename U> sp<T>::sp(const sp<U>& other) : m_ptr(other.m_ptr) { if (m_ptr) m_ptr->incStrong(this); }
同类型是指模板类型为T,赋值过来参数也是T类型,异类行是指模板类型为T,而传递参数类型为U。
其所有的操作均是分为这两种类型来定义实现的,而WP的类中也是分3种情况的,因为除了这两种情况外,还需要从SP传递过来。一个对象一定是个强引用,但是其可以改为弱引用,这句是WP比SP多一种类型的原因。
2种类型的赋值与拷贝从赋值构造函数也可以看出,具体跟复制构造函数一个样。有一个很奇怪的问题是,这几个类中居然没有对*和->的重载操作。不明白为什么。
SP中的一个操作如下:
template<typename T> sp<T>& sp<T>::operator = (const sp<T>& other) { T* otherPtr(other.m_ptr); if (otherPtr) otherPtr->incStrong(this); if (m_ptr) m_ptr->decStrong(this); m_ptr = otherPtr; return *this; }
一开始我也没有搞明白为啥这样,看了一会才明白,非常类似与STL中的SmartPoint,把other赋过来,首先将other本身的强引用增加,然后将本身的强应用减去,因为“权力”变了,减完之后,赋值。
WP就不再贴了,帖子长了自己都懒得看了,不过基本内容差不多,成员变量多了一个m_refs,这个指针主要操作弱引用部分。然后一个比较长的函数是promote函数,根据上边提到的不同情况,看是否可以将弱引用转为强引用。
其实一开始就没太搞明白这几层的关系,突然感觉C++都白学了,看了点例子,然后把这几个文件抠出来(这些与底层无关,把一些原子操作自己改掉了)用VS编译,测试,然后才有点小明白,如果直接在Android里编的话,当然我没试过,不过看书上讲可以调试框架,没尝试,先搞明白这底层的这点东西吧。
插一句,后来测试的时候发现一个类(只有函数,没有变量)中只要有虚函数,那么这个类默认大小为4个字节,如果没有,默认为一个字节
参考的文章:http://www.blogjava.net/mixer-a/archive/2012/04/17/374985.html