Java 和 C/C++的一个重大区别,就是它没有“指针”的概念。这并不代表 Java 不需要使用指针,而是被隐藏了起来。如果使用 C/C++开发过一些大型项目,就会知道开发人员最头疼的事情莫过于概率性极低 的死机问题一一而造成系统宕机的根源,往往就是指针异常。所以 Java 以其他更安全的形式向开发人员提供了隐性的指针,使得用户既能享受到指针的强大功能,又能尽量避免指针带来的灾难。
C/C++项目中常见的指针问题可以归纳为:
既然 C/C++中的指针有如此难以控制,那么如何对它进行改善呢? 在分析 Android 中智能指针的实现原理前,如果让我们自己来设计智能指针,该怎么做呢? 如何设计一个能有效防止以上几个致命弱点的智能指针方案。
要让智能指针自动判断是否需要回收一块内存空间,应该如何设计? 以下我们称内存对象为 object,称智能指针为 SmartPointer。
class SmartPointer
{
private:
void * m_ptr;//指向object对象
}
template <typename T>
class SmartPointer
{
private:
T * m_ptr;//指向object 对象
}
template <typename T>
class SmartPointer
{
inline SmartPointer() : m_ptr(0){ }
private:
T * m_ptr; //将指向 object
}
如果当前只有一个智能指针引用了 object,看上去并没有什么大问题。那么,如果有两个(或以上)的智能指针都需要使用 object 呢? 如下图:
当SmartPointer1 释放了自己与 object 的连接后,mCount-1,这时候发现计数值已经为0,所以根据设计需要去 delete object。然而,此时SmartPointer2 却还在使用 object,显然这将引发致命的问题。
可以为有计数器需求的内存对象实现一个统一的“父类”,这样只要 object 继承于它就具备了计数的功能。比如下面的范例:
template <class T>
class LightRefBase
{
public:
inline LightRefBase() : mCount(0) { }
//增加引用计数
inline void incStrong(__attribute__((unused)) const void* id) const {
__sync_fetch_and_add(&mCount, 1);
}
//减小引用计数
inline void decStrong(__attribute__((unused)) const void* id) const {
if (__sync_fetch_and_sub(&mCount, 1) == 1) {
delete static_cast<const T*>(this);
}
}
//! DEBUGGING ONLY: Get current strong ref count.
inline int32_t getStrongCount() const {
return mCount;
}
typedef LightRefBase<T> basetype;
protected:
inline ~LightRefBase() { }
private:
friend class ReferenceMover;
inline static void moveReferences(void*, void const*, size_t,
const ReferenceConverterBase&) { }
private:
mutable volatile int32_t mCount; //引用计数值
};
以上代码段中的 LightRefBase 类主要提供了两个方法,incStrong 和 decStrong,分别用于增加和减少引用计数值。而且如果当前已经没有人引用内存对象(计数值为 0),它还需要自动释放自己。
那么,incStrong 和 decStrong 这两个函数在什么情况下会被调用呢? 既然是引用计数,当然是在“被引用时”,所以这个工作应该由 SmartPointer 完成。如下所示:
SmartPointer<TYPE> smartP = new object;
当一个智能指针引用了 object 时,其父类中的 incStrong 就会被调用。所以 SmartPointer 必须要重载它的 “=” 运算符(多数情况下只重载 “=” 是不够的,应视具体设计需求而定)。
template <typename T>
class SmartPointer
{
inline SmartPointer() : m_ptr(0){ }
~wp();
SmartPointer& operator = (T* other);//运算符重载
private:
T * m_ptr; //将指向 object
}
template<typename T>
SmartPointer<T>&SmartPointer<T>::operator = (T* other)
{
if(other != null)
{
m_ptr = other; //指向内存对象
other-> incStrong(); //主动增加计数值
}
return *this;
}
//当SmartPointer析构时,调用decStrong释放引用
template<typename T>
wp<T>::~wp()
{
if (m_ptr)m _ptr->decStrong();
}
所以,他们直接的关系图为:
解决了第2个问题,实际上第3个问题也解决了。引用计数器的出现使得放内存对象不再是个别指针的事情,而是对象自己的“内政”,只要有人在使用它,它就不会轻易 delete 自身,也就有效地避免了引用它的指针突然变成“野指针”的情况。
通过上面这个例子,就能很好理解智能指针的实现逻辑了,后面在分析Android 中的智能指针(sp、wp)实现,就更得心应手啦。
看到 sp 并非 SmartPointer 的缩写,而是 StrongPointer 的简写。经过几次系统改版后,sp 这个类已经被完全移出了 RefBase.h 文件。Android 9源码工程中 sp 类的位置在:
system/core/libutils/include/utils/StrongPointer.h
而 wp 以及上一节所讲述的 LightRefBase 都仍在 RefBase.h 中。下面来看看 sp 类中一些重要的接口实现:
template <typename T>
class sp
{
public:
inline sp() : m_ptr(0) { }
sp(T* other); // NOLINT, implicit
sp(const sp<T>& other);
template<typename U> sp(U* other); // NOLINT, implicit
template<typename U> sp(const sp<U>& other); // NOLINT, implicit
~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;
};
它和前一节的 SmartPointer 类在实现上基本是一致的。比如运算符等号的实现为:
template<typename T>
sp<T>& sp<T>::operator = (T* other)
{
if (other) other->incStrong(this);//增加引用计数
if (m_ptr) m_ptr->decStrong(this);
m_ptr = other;
return *this;
}
上面这段代码同时考虑了对一个智能指针重复赋值的情况。即当 m_ptr 不为空时,要先撤销它之前指向的内存对象,然后才能赋予其新值。另外,为 sp 分配一个内存对象并不一定要通过操作运算符,它的构造函也是可以的。
template<typename T>
sp<T>::sp(T* other)
: m_ptr(other)
{
if (other) other->incStrong(this);//因为是构造函数,不用担心m_ptr之前已经赋过值
}
这时 m_ptr 就不用先置为 null,可以直接指向目的对象,而析构函数的做法和我们的预想也是一样的:
template<typename T>
sp<T>::~sp()
{
if (m_ptr) m_ptr->decStrong(this);
}
总之,强指针 sp 的实现和前一节的例子基本相同。
什么是弱指针呢?想象这样一个场景:父对象 parent 指向子对 child,然后子对象又指向父对象,这就存在了循环引用的现象。
比如有如下两个结构体:
struct CDad
{
CChild* myChild;
}
struct CChild
{
CDad* myDad;
}
那么,很可能会产生下图所示的关系。
如果不考虑智能指针,这样的情况并不会导致任何问题。但是在智能指针的场景下,有没有特别要注意的地方呢? 假设这两个类都具有引用计数器的功能:
这有点类似于操作系统中的死锁一一因为内存回收者发现两者都是处于“被需要”的状态当然不能释放,从而形成了恶性循环。
解决这个矛盾的一种有效方法是采用“弱引用”。具体措施如下:
CDad 使用强指针来引用CChild,而CChild 只使用弱引用来指向父类。 双方规定当强引用计数为0时,不论弱引用是否为 0都可以 delete 自己(在 Android 系统中这个规则是可以调整的后面会介绍)。这样只要有一方得到了释放,就可以成功避免死锁。
但是,会不会导致野指针的问题?比如 CDad 因为强指针计数已经到0,根据规则生命周期就结束了;但此时 CChild 还持有其父类的弱引用,显然如果CChild 此时用这个指针来访问 CDad 将引发致命的问题。鉴于此,我们还要特别规定:
template <typename T>
class wp
{
public:
typedef typename RefBase::weakref_type weakref_type;
inline wp() : m_ptr(0) { }
explicit wp(T* other);
wp(const wp<T>& other);
explicit wp(const sp<T>& other);
template<typename U> explicit wp(U* other);
template<typename U> explicit wp(const sp<U>& other);
template<typename U> explicit wp(const wp<U>& other);
~wp();
// Assignment
//运算符重载"="
wp& operator = (T* other);
wp& operator = (const wp<T>& other);
wp& operator = (const sp<T>& other);
template<typename U> wp& operator = (U* other);
template<typename U> wp& operator = (const wp<U>& other);
template<typename U> wp& operator = (const sp<U>& other);
void set_object_and_refs(T* other, weakref_type* refs);
// 升级为强指针sp
sp<T> promote() const;
// Reset
void clear();
// Accessors
inline weakref_type* get_refs() const { return m_refs; }
inline T* unsafe_get() const { return m_ptr; }
// Operators
COMPARE_WEAK(==)
COMPARE_WEAK(!=)
COMPARE_WEAK(>)
COMPARE_WEAK(<)
COMPARE_WEAK(<=)
COMPARE_WEAK(>=)
inline bool operator == (const wp<T>& o) const {
return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
}
template<typename U>
inline bool operator == (const wp<U>& o) const {
return m_ptr == o.m_ptr;
}
inline bool operator > (const wp<T>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
}
template<typename U>
inline bool operator > (const wp<U>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
}
inline bool operator < (const wp<T>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
}
template<typename U>
inline bool operator < (const wp<U>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
}
inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
inline bool operator >= (const wp<T>& o) const { return !operator < (o); }
template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }
private:
template<typename Y> friend class sp;
template<typename Y> friend class wp;
T* m_ptr;
weakref_type* m_refs;
};
和 sp 相比,wp 在类定义上有如下重要区别:
其构造函数为:
template<typename T>
wp<T>::wp(T* other)
: m_ptr(other)
{
if (other) m_refs = other->createWeak(this);
}
与强指针中的构造方法相比:
template<typename T>
sp<T>::sp(T* other)
: m_ptr(other)
{
if (other) other->incStrong(this);//因为是构造函数,不用担心m_ptr之前已经赋过值
}
可见 wp 并没有直接增加目标对象的引用计数值,而是调用了 createWeak 方法。这个函数属于前面提到的 RefBase 类,如下所示:
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 //内部类,wp中用到此类
{
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()
//以下参数用于修改object生命周期
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,也就是前面 m_refs 指针所属的类型。RefBase 中还有一个类型为 weakref_impl 的成员变量mRefs,从名称上来看,它应该是 weakref_type 的实现类:
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
std::atomic<int32_t> mStrong;//强引用计数值
std::atomic<int32_t> mWeak;//弱引用计数值
RefBase* const mBase;
std::atomic<int32_t> mFlags;
#if !DEBUG_REFS //不是debug的情况下
explicit 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 renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
void addWeakRef(const void* /*id*/) { }
void removeWeakRef(const void* /*id*/) { }
void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
void printRefs() const { }
void trackMe(bool, bool) { }
#else //debug的情况下
weakref_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)
{
}
......
#endif //DEBUG_REFS宏结束
}; //RefBase::weakref_impl类结束
从开头的几个变量可以大概猜出 weakref_impl 所做的工作,其中 mStrong 用于强引用计数,mWeak 用于弱引用计数。
宏 DEBUG_REFS 用于指示release 或 debug 版本。可以看到在 release 版本下,addStrongRef,removeStrongRef 等与 Ref 相关的一系列方法都没有具体实现。也就是说,这些方法实际上是用于调试的,在分析时完全可以不用理会。这样一来整个分析也明朗了很多。
Debug 和 Release 版本都将 mStrong 初始化为INITIAL_STRONG_VALUE。这个值的定义如:
#define INITIAL_STRONG_VALUE (1<<28)
而 mWeak 则初始化为 0。
上面#else 到#endif 之间的部分都是 debug 版本要做的工作,所以都可以略过不看。因而上述代码段中并没有引用计数器相关的控制实现,真正有用的代码在类声明的外面。比如我们在 wp构造函数中遇到的 createWeak 函数:
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
mRefs->incWeak(id);
return mRefs;
}
这个函数先增加了 mRefs(也就是 weakref_impl 类型的成员变量)中的引用计数值,然后返回这个mRefs。
其关系如下图所示:
首先 wp中的 m_ptr 还是要指向目标对象(继承自 RefBase)。RefBase 的作用类似于前面讨论的 LightRefBase,只不过它还同时提供了弱引用控制以及其他新的功能。
和 LightRefBase 不同,RefBase 不是直接使用 int 变量来保存引用计数值,而是采用了weakref_type 类型的计数器。因为 ReBase 需要处理多种计数类型。另外,wp 中也同时保存了这个计数器的地址,也就是 wp 中的 m_refs 和 RefBase 中的 mRefs 都指向了计数器。其中 wp 是通过在构造函数中调用目标对象的 createWeak 来获得计数器地址的,而计数器本身是由 RefBase在构造时创建的。
整个 wp 机制看起来很复杂,但与强指针相比实际上只是启用了一个新的计数器 weakref_impl而已,其他所有工作都是围绕如何操作这个计数器而展开的。接下来的重点就是看看这几个类是如何利用新计数器来达到设计目标的。
需要强调的是,虽然 weakref_impl 是 RefBase 的成员变量,但是wp 也可以直接控制它,所以整个逻辑显得稍微有点混乱,估计是为了兼容以前版本而遗留下来的问题。
在createWeak 中,mRefs 通过 incWeak 增加了计数器的弱引用。即:
void RefBase::weakref_type::incWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->addWeakRef(id);//用于调试目的
//真正起作用函数,增加了mWeak 计数器值
const int32_t c __unused = impl->mWeak.fetch_add(1,
std::memory_order_relaxed);
ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
这个函数真正有用的语句就是const int32_t c __unused = impl->mWeak.fetch_add(1, std::memory_order_relaxed),它增加了mWeak 计数器值,而其他部分都与调试相关,可以略过。这样当 wp 构造完成以后,RefBase 所持有的 weakref_type 计数器中的 mWeak 就为1。后面如果有新的 wp 指向这个目标对象,mWeak 还会持续增加。
而如果是 sp 指向它呢? 在上一小节中分析过,这时 sp 会调用目标对象的 incStrong 方法来增加强引用计数值。当目标对象继承自 RefBase 时,这个函数的实现是:
void RefBase::incStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->incWeak(id);//增加弱指针计数值
refs->addStrongRef(id);
const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);//增加强引用计数值
ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
#if PRINT_REFS
ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
if (c != INITIAL_STRONG_VALUE) {//判断是不是第一次
return;//不是第一次就直接返回
}
int32_t old __unused = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE, std::memory_order_relaxed);
// A decStrong() must still happen after us.
ALOG_ASSERT(old > INITIAL_STRONG_VALUE, "0x%x too small", old);
refs->mBase->onFirstRef();
}
首先剔除与调试相关的语句,真正的操作如下:
refs->incWeak(id);//增加弱指针计数值
const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);//增加强引用计数值
也就是同时增加弱引用和强引用计数值。然后还要判断目标对象是不是第一次被引用,其中的c变量得到的是“增加之前的值”,因而如果等于INITIAL_STRONG_VALUE 就说明是第一次(这时候一方面要回调 onFirstRef通过对象自己被引用,另一方面要对 mStrong 值做调整。)为什么呢?
因为 mStrong 先是被置了INITIAL_STRONG_VALUE = 1<<28,那么当第一次增加时它就是 1<<28+1,所以还要再次减掉INITIAL_STRONG_VALUE 才能得到1。
了解强弱指针对计数器的操作后,再来分析下目标对象在什么情况下会被释放。无非就是考查减少强弱引用时系统所遵循的规则,如下所示是 decStrong 的情况。
void RefBase::decStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->removeStrongRef(id);//调试目的
const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);//减少强引用计数
#if PRINT_REFS
ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
LOG_ALWAYS_FATAL_IF(BAD_STRONG(c), "decStrong() called on %p too many times",
refs);
if (c == 1) {//减少后强引用计数值已经降为0
std::atomic_thread_fence(std::memory_order_acquire);
refs->mBase->onLastStrongRef(id);//通知事件
int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
delete this;//删除对象
// The destructor does not delete refs in this case.
}
}
refs->decWeak(id);//减少弱引用计数
}
首先减少 mStrong 计数器,如果发现已经减到0(即c-=1),就需要回调 onLastStrongRef通知这一事件,接着执行删除操作(如果标志是OBJECT_LIFETIME_STRONG的话)。特别要注意,减小强引用计数值时还要同时减小弱引用计数值,即最后的 decWeak(id)。其实现如下:
void RefBase::weakref_type::decWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->removeWeakRef(id);//调试目的
const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);//减少弱引用计数值
LOG_ALWAYS_FATAL_IF(BAD_WEAK(c), "decWeak called on %p too many times",
this);
//先减小 mWeak 计数值,如果发现还不为 0(即 c!=1),就直接返回;
//否则就是弱引用计数值也为0,此时要根据 LIFETIME 标志分别处理。
if (c != 1) return;
atomic_thread_fence(std::memory_order_acquire);
int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
// This is the regular lifetime case. The object is destroyed
// when the last strong reference goes away. Since weakref_impl
// outlives the object, it is not destroyed in the dtor, and
// we'll have to do it here.
if (impl->mStrong.load(std::memory_order_relaxed)
== INITIAL_STRONG_VALUE) {
// Decrementing a weak count to zero when object never had a strong
// reference. We assume it acquired a weak reference early, e.g.
// in the constructor, and will eventually be properly destroyed,
// usually via incrementing and decrementing the strong count.
// Thus we no longer do anything here. We log this case, since it
// seems to be extremely rare, and should not normally occur. We
// used to deallocate mBase here, so this may now indicate a leak.
ALOGW("RefBase: Object at %p lost last weak reference "
"before it had a strong reference", impl->mBase);
} else {
// ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
delete impl;
}
} else {
// This is the OBJECT_LIFETIME_WEAK case. The last weak-reference
// is gone, we can destroy the object.
impl->mBase->onLastWeakRef(id);
delete impl->mBase;
}
}
上面这段代码是弱引用的处理核心,主要基于以下标志来处理。
enum {
OBJECT_LIFETIME_STRONG = 0x0000,
OBJECT_LIFETIME_WEAK = 0x0001,
OBJECT_LIFETIME_MASK = 0x0001
};
每个目标对象都可以通过以下方法来更改它的引用规则。
void RefBase::extendObjectLifetime(int32_t mode)
{
// Must be happens-before ordered with respect to construction or any
// operation that could destroy the object.
mRefs->mFlags.fetch_or(mode, std::memory_order_relaxed);
}
实际上就是改变了 mFlags 标志值(默认情况下它是0,即OBJECT_LIFETIME_STRONG) 所以当flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG时,即释放规则受强引用控制的情况。
有个问题,既然是强引用控制,那弱引用还要做什么工作呢?
理论上它确实可以直接返回了,不过还有些特殊情况。前面在 inStrong 函数里,我们看到它同时增加了强、弱引用计数值。而增加弱引用时是不会同时增加强引用的,这说明:弱引用的值>=强引用值。当程序走到这里,弱引用计数值一定为 0,而强引用值有两种可能。
那么,为什么是在这里 delete 这个计数器呢? weakref_impl 既然是由 RefBase 创建的,那么按理来说也应该由它来删除。实际上 RefBase 也想做这个工作,只是力不从心。其析构函数如下:
RefBase::~RefBase()
{
int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
// Life-time of this object is extended to WEAK, in
// which case weakref_impl doesn't out-live the object and we
// can free it now.
if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
// It's possible that the weak count is not 0 if the object
// re-acquired a weak reference in its destructor
// 看这里
if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
delete mRefs;
}
} else if (mRefs->mStrong.load(std::memory_order_relaxed)
== INITIAL_STRONG_VALUE) {
// We never acquired a strong reference on this object.
LOG_ALWAYS_FATAL_IF(mRefs->mWeak.load() != 0,
"RefBase: Explicit destruction with non-zero weak "
"reference count");
// TODO: Always report if we get here. Currently MediaMetadataRetriever
// C++ objects are inconsistently managed and sometimes get here.
// There may be other cases, but we believe they should all be fixed.
delete mRefs;
}
// For debugging purposes, clear mRefs. Ineffective against outstanding wp's.
const_cast<weakref_impl*&>(mRefs) = NULL;
}
在这种情况下,RefBase 既然是由 decStrong 删除的,那么从上面 decStrong 的执行顺序上来看mWeak 值还不为0,因而并不会被执行。
如果是弱引用控制下的判断规则(即OBJECT_LIFETIME_WEAK),其实和deStrong 中的处理一样,要首先回调通知目标对象这一事件,然后才能执行删除操作。
分析完了Android 系统中的智能指针源码实现。总结: