继上篇我们学习了 Android 轻量级指针的实现,是时候来看“重量级”指针的实现了。在 Android 里,“重量级”指针指的是 RefBase
和 sp/wp
配合使用的情况,它提供了完整的强、弱指针的支持。
考虑这样一种情况,A 持有 B,B 持有 A,C 持有 A。如果只使用简单的引用计数,在 C 释放 A 后,A、B 各自的计数值都为 1,永远不会被销毁,也无法再访问。这就是经典的循环引用问题。
引入弱指针后,我们可以让 A 持有 B 的强指针,而 B 指持有 A 的弱指针。这样一来,在 C 释放 A 后,A 的引用计数将降为 0 从而被销魂;A 销毁的同时,A 所持有的 B 的强指针也会销毁,于是 B 的引用计数也降为 0,B 被销毁。
了解了这些基础知识后,下面我们就来看看 RefBase
的源码
RefBase
类定义
这里我先把 RefBase
的定义摆上来,后面我们捡最重要的几个看。
// system/core/libutils/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);
// acquires a strong reference if there is already one.
bool attemptIncStrong(const void* id);
// acquires a weak reference if there is already one.
// This is not always safe. see ProcessState.cpp and BpBinder.cpp
// for proper use.
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);
}
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
};
// Invoked after creation of initial strong pointer/reference.
virtual void onFirstRef();
// Invoked when either the last strong reference goes away, or we need to undo
// the effect of an unnecessary onIncStrongAttempted.
virtual void onLastStrongRef(const void* id);
// Only called in OBJECT_LIFETIME_WEAK case. Returns true if OK to promote to
// strong reference. May have side effects if it returns true.
// The first flags argument is always FIRST_INC_STRONG.
// TODO: Remove initial flag argument.
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
// Invoked in the OBJECT_LIFETIME_WEAK case when the last reference of either
// kind goes away. Unused.
// TODO: Remove.
virtual void onLastWeakRef(const void* id);
private:
friend class weakref_type;
class weakref_impl;
RefBase(const RefBase& o);
RefBase& operator=(const RefBase& o);
private:
weakref_impl* const mRefs;
};
在看他的函数的实现前,我们先对比一下 LightRefBase
,看看他们两个有什么不同。首先最明显的是,RefBase
不是一个类模板,这个我们在上篇已经提到了;也因此 RefBase::~RefBase
是一个虚函数。其次,RefBase
还定义了一个 weakref_type
,他的真正实现是 weakref_impl
,所有的引用计数都记录在 weakref_impl
里。
好事者这个时候就要问了,为什么 RefBase
不像 LightRefBase
把引用计数直接用成员变量来存储?(人家这么写,肯定是有理由的呀)这里的关键就在弱指针上。当用户持有弱指针的时候,需要提供一种途径,让他尝试转换成强指针。如果把引用计数等信息都存放在 RefBase
里,当对象已经销毁但有弱指针指向它的时候,