前言
Java 和 C/C++ 的一个重大区别,就是它没有"指针"的概念,这并不代表 Java 不需要只用指针,而是将这个"超级武器隐藏了"。Java 以其他更"安全"的形式向开发人员提供了隐形的"指针",使得用户既能享受到指针的强大功能,又能尽量避免指针带来的问题。
C/C++中常见的指针问题
- 指针没有初始化
对指针进行初始化是程序员必须养成的良好习惯,也是指针问题中最容易解决和控制的一个问题;
- new 了对象没有及时 delete
动态分配内存的对象,其实声明周期的控制不当常常会引起不少麻烦。如果只有一个程序员在维护时,问题通常不大,因为只要稍微留心就可以实现 new 和 delete 的配套操作;但是如果一个大型工程,就很可能会出现动态分配的内存没有回收的情况——造成的内存泄露问题往往是致命的;
- 野指针
假设1:我们 new 了一个对象 A,并将指针 ptr 指向这个新的对象。当对 A 使用结束后,我们也主动 delete 了 A,但是唯一没做的是将 ptr 指针置空,那么可能出现野指针问题。因此如果有"第三方"视图用 ptr 来使用内存对象,它首先通过判断发现 ptr 不为空,就认为这个对象还是存在的,其结果就是导致程序崩溃或是数据错误;
假设2:假设 ptr1 和 ptr2 都指向对象 A,后来我们通过 ptr1 释放了 A 的内存空间,并且将 ptr1 也置为 null;但是 ptr2 并不知道它所指向的内存对象已经不存在了,此时如果 ptr2 来访问 A 也会导错误;
Android 智能指针
在开发中经常会使用对象引用计数来维护对象的生命周期,而该技术的核心问题是由谁来维护对象的引用计数,由开发人员维护显然既不可靠,又不方便编写和维护。而智能指针正是一种可以自动维护对象引用计数的计数,需要注意的是,智能指针是一个对象,而不是一个指针。
现在考虑这样一个问题:
有两个对象 A 和 B,A 引用了 B,同时 B 也引用了 A。当对象 A 不再使用时,就可以释放它所占用的内存,但是由于 B 还持有 A 的引用,结果就是 A 不能被释放。对于释放 B 的资源时也会遇到
同样的问题而不能得到释放。这个问题也是垃圾回收系统所遇到的经典问题之一,因为它一次只能收集一个对象占用的内存(还要看的具体的回收机制)。
这就要使用一种特殊的智能指针技术,该技术将对象的引用计数分为强引用计数和弱引用计数两种,其中对象生命周期只受强引用计数控制。在使用以上引用计数方式时,一般将有关联的对象划分为“父——子”和“子——父”关系。“父”对象通过强引用来引用“子”对象,“子”对象通过弱引用来引用“父”对象。
以上面的 A 和 B 对象为例,假设 A 和 B 是“父——子”关系,对象 A 通过强引用来引用 B,而 B 通过弱引用来引用 A。当对象 A 不再使用的时,由于 B 使用过弱引用来引用 A 的,而 对象的生命周期只受强引用计数控制,所以,A 的生命周期不受 B 的影响,可以安全释放。在释放 A 的同时,也会释放它对 B 的强引用计数,因此 B 再不需要时可以被安全释放。
由于对象生命周期只受强引用计数控制,因此在 B 想要使用 A 时,A 可能已经被释放了,这个时候 B 不能直接使用 A 对象,而是先要成功的将对象 A 的弱引用计数升级为强引用计数,然后才能使用 A;如果引用计数升级失败,那么 B 就无法使用 A 了。
Android 系统设计了三种类型的 C++ 智能指针,分别为:
- 轻量级指针:Light Pointer
- 强指针:Strong Pointer
- 弱指针:Weak set_pointer
其中轻量级指针使用了简单引用计数,而强指针和弱指针使用了强引用计数和引用计数。
Android 提供了基类 RefBase,用以管理引用数,所有支持使用强指针和弱指针的类必须从 RefBase 派生。设计模板类 sp、wp,用以引用实际对象,sp、wp 声明为栈对象,作用域结束时,自动释放,自动调用机析构函数。因此可以在 sp、wp 的构造函数中,增加引用计数,在析构函数中,减少引用计数。专门设计的 weakref_impl 类,该类是 RefBase 的内部类,用来做真正的引用数管理,都由 mRef 来管理。
Android智能指针的关系图:
Android智能指针的源码位置
android中的智能指针的主要代码是:RefBase.h、RefBase.cpp 以及 Pointer.h 这三个文件,他们分别位于:
RefBase.cpp: /system/core/libutils/RefBase.cpp
RefBase.h: /system/core/include/utils/RefBase.h
StrongPointer.h:/system/core/include/utils/StrongPointer.h
轻量级指针
这里不多提轻量级指针,因为这种指针式通过简单引用计数技术来维护对象生命周期的。关于它只需知道一下 3 点:
-
第一点使用它需要继承 LightRefBase(模板类);
public LightClass: public LightRefBase<LightClass>
第二点 LightRefBase 类只有一个成员变量 mCount 用来描述一个对象的引用计数值;
第三点需要知道轻量级指针的实现类和强指针的实现类是同一个类 sp。
强指针和弱指针
强指针和弱指针通过强引用计数器和弱引用计数器来维护对象的生命周期。如果一个类的对象要使用强指针和弱指针,那么就必须从 RefBase 类继承下来,因为 RefBase 类提供了强引用和弱引用计数器。
强指针和弱指针关系比较密切,他们是配合在一起使用的。
强指针的实现原理分析
首先分析 RefBase 类的实现原理,源码如下:
源码位置:Android源码目录/system/core/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
};
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);
private:
friend class ReferenceMover;
static void renameRefs(size_t n, const ReferenceRenamer& renamer);
static void renameRefId(weakref_type* ref,
const void* old_id, const void* new_id);
static void renameRefId(RefBase* ref,
const void* old_id, const void* new_id);
weakref_impl* const mRefs; // 描述对象引用计数
};
RefBase 提供了成员函数 incStrong 和 decStrong 来维护他所引用的对象的引用计数,这是通过使用一个 weakref_impl 对象,即成员变量 mRefs 来描述对象的引用计数。
weakref_impl 同时为类提供了强引用和弱引用计数,源码如下:
源码位置:Android源码目录 /system/core/libutils/RefBase.cpp
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
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
......
#endif
};
weakref_impl 继承了 weakref_type 类,weakref_type 为 RefBase 内部类,它提供了成员函数:incWeak、decWeak、attemptIncStrong 和 attemptIncWeak 来维护对象的
强引用计数和弱引用计数。weakref_type 只提供了方法接口,具体实现由 weakref_impl 完成。
weakref_impl 有两个成员变量 mStrong 和 mWeak,分别描述对象的强引用计数和弱引用计数。weakref_impl 的成员变量 mBase 指向了它所引用的对象的地址, 成员变量 mFlags 是一个标志值,用来描述对象的生命周期的控制方式。mFlags 的去值范围为:OBJECT_LIFETIME_STRONG、OBJECT_LIFETIME_WEAK 或是
OBJECT_LIFETIME_FOREVER,其中 OBJECT_LIFETIME_STRONG 表示对象的生命周期只受到强引用计数的影响;OBJECT_LIFETIME_WEAK 表示对象的生命周期同时受到强引用计数和弱引用计数的影响;OBJECT_LIFETIME_FOREVER 表示完全不受强引用计数和弱引用计数的影响。
以上三个类关系如下:
强指针实现类 sp
强指针的实现类为 sp,下面主要分析它的构造蛤蟆数和析构函数。
sp 源码如下:
源码位置:Android源码目录/system/core/include/utils/StrongPointer.h
template<typename T>
class sp {
public:
inline sp() : m_ptr(0) { }
sp(T* other);
sp(const sp<T>& other);
sp(sp<T>&& other);
template<typename U> sp(U* other);
template<typename U> sp(const sp<U>& other);
template<typename U> sp(sp<U>&& other);
~sp();
// Assignment
sp& operator = (T* other);
sp& operator = (const sp<T>& other);
sp& operator = (sp<T>&& other);
template<typename U> sp& operator = (const sp<U>& other);
template<typename U> sp& operator = (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 构造函数
sp 的构造函数如下:
源码位置:Android源码目录/system/core/include/utils/StrongPointer.h
template<typename T>
sp<T>::sp(T* other)
: m_ptr(other) {
if (other)
other->incStrong(this);
}
模块参数 T 继承了 RefBase 类的子类,因此,以上代码实际上会调用 RefBase 的成员函数 incStrong 来增加对象的强引用计数,如下所示:
源码位置:Android源码目录/system/core/libutils/RefBase.cp
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 = 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();
}
RefBase 的成员变量 mRefs 是在构造函数中初始化的,如下所示:
RefBase::RefBase()
: mRefs(new weakref_impl(this))
{
}
接着分析 RefBase 的 incStrong 函数,它主要做了三件事:
- 增加对象的弱引用计数;
- 增加对象的强引用计数;
- 如果对象是第一次被强指针引用,调用成员函数 onFirstRef 来通知对象,它被强指针引用了,以便可以执行一些业务逻辑。
增加对象弱引用计数是通过调用 RefBase 的成员变量 mRefs(也就是 weakref_impl)的成员函数 incWeak 来实现的,它是 weakref_type 的子类,函数 incWeak 是从其父类继承下来的,
weakref_type 中 incWeak 代码如下:
void RefBase::weakref_type::incWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->addWeakRef(id); // 调试相关,忽略
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);
}
这里 this 指针实际上是指向一个 weakref_impl 对象,因此将其转化为 weakref_impl 指针,接下来增加它的成员变量 mWeak 的值,即增加对象的弱引用计数。
增加了对向的弱引用后,接着就增加对象的强引用计数,也就是增加 mRefs 的成员变量 mStrong 的值。并返回对象原来的强引用计数值,即加一前的值。在 weakref_impl 的构造函数中,成员
变量 mStrong 的值被初始化为 INITIAL_STRONG_VALUE。INITIAL_STRONG_VALUE 是一个宏,其定义如下:
#define INITIAL_STRONG_VALUE (1<<28)
理论上,对象第一次被强指针引用时,它的强引用计数应该为 1,但是 INITIAL_STRONG_VALUE + 1 的值并不等于 1,因此,RefBase 类的成员函数 incStrong 就需要将它的值调整为 1 这
是通过
int32_t old = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,std::memory_order_relaxed);
实现的。
至此 sp 的构造函数分析完了,它主要做的事就是增加强引用计数和弱引用计数。
下分析 sp 的析构函数。
sp 析构函数
析构函数代码如下:
源码位置:Android源码目录/system/core/include/utils/StrongPointer.h
template<typename T>
sp<T>::~sp() {
if (m_ptr)
m_ptr->decStrong(this);
}
m_ptr 所指向的对象是继承了 RefBase 的类,所以这里实际上调用了 RefBase 的 decStrong 函数来减少对象的强引用计数,其实现如下:
源码位置:Android源码目录/system/core/libutils/RefBase.cpp
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
ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
if (c == 1) {
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;
}
}
refs->decWeak(id);
}
sp 析构函数的主要工作就是减少对象强引用计数和弱引用计数。与其构造函数一样
const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
也是返回原来的强引用计数,即减1前的值,并保存在了变量 c 中。如果变量 c 的值等于1,也就是说,此时没有强指针引用这个对象了,接下来就可以调用
refs->mBase->onLastStrongRef(id);
来执行一些业务相关逻辑,同时也需要考虑是否需要释放该对象。接下来判断对象的生命周期是否只受强引用控制,如果是,那么就下来就会释放对象所占用的内存,同时导致 RefBase 的
析构函数被调用,代码如下:
源码位置:Android源码目录/system/core/libutils/RefBase.cpp
RefBase::~RefBase()
{
if (mRefs->mStrong.load(std::memory_order_relaxed)
== INITIAL_STRONG_VALUE) {
delete mRefs;
} else {
int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
// 生命周期不只是受强引用计数控制
if ((flags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
delete mRefs;
}
}
}
// 只受强引用计数控制,只释放 RefBase,保留 mRefs
const_cast<weakref_impl*&>(mRefs) = NULL;
}
如果强引用计数为初始值,也就是说该对象没有被强指针引用过,那么释放成员变量 mRefs(weakref_impl);当强引用计数为 0,但是弱引用不为 0时,只能将对象 RefBase 释放掉,而不能将 weakref_impl
对象 mRefs 释放掉,因为还有其他的弱指针通过该 weakref_impl 对象来引用实际对象。只有对象的弱引用计数为 0 时,才可以将 weakref_impl 一起释放掉。
回到函数 decStrong 中,接下来通过
refs->decWeak(id);
减少弱引用计数。refs 是 weakref_impl 对象,weakref_impl继承自 weakref_type,这里实际会调用 weakref_type 的 decWeak 函数,代码如下:
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);
ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
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) {
if (impl->mStrong.load(std::memory_order_relaxed)
== INITIAL_STRONG_VALUE) {
// Special case: we never had a strong reference, so we need to
// destroy the object now.
delete impl->mBase;
} else {
// ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
delete impl;
}
} else {
impl->mBase->onLastWeakRef(id);
delete impl->mBase;
}
}
函数
impl->mWeak.fetch_sub(1, std::memory_order_release);
会返回对象的原弱引用计数,即减1前的值,并存放在变量 c 中,如果 c 不为 1,也就是说还有其他弱指针指向该对象,因此就不做进一步处理;如果 c 的值等于 1,也就是说没有其他弱指针指引用
该对象了,同时也说明没有强指针引用该对象了,这是需要考虑是否释放掉该对象。这取决于对象生命周期的控制方式,以及该对象是否被强指针引用过。下面分两种情况讨论。
对象生命周期只受强引用计数控制,即 (flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG 为 true,如果此时 impl->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE 也为 true,也就是说该对象没有被强指针引用过,那么就可以将该对象释放掉。如果对象的生命周期只受强引用计数控制,并且也被强指针引用过,那么在该对象的弱引用计数变为 0 时,该对象就已经在 RefBase 的成员函数 decStrong 中被释放掉了,因此,接下来就只释放其内部的引用计数器对象 weakref_impl。
生命周期受弱引用控制,,那么接下来就可以调用 onLastWeakRef 来处理一些业务相关逻辑,接着将将该对象释放掉。
总结
- 如果一个对象的生命周期只受到强引用控制,那么只要它的强引用计数值为 0,系统就会释放掉该对象;
- 如果一个对象的生命周期控制标志被设置为 OBJECT_LIFETIME_WEAK,只有当强引用计数和弱引用计数都是 0时,系统才会释放掉这个对象。
弱指针的实现原理分析
wp 类的定义如下;
template <typename T>
class wp
{
public:
typedef typename RefBase::weakref_type weakref_type;
inline wp() : m_ptr(0) { }
wp(T* other);
wp(const wp<T>& other);
wp(const sp<T>& other);
template<typename U> wp(U* other);
template<typename U> wp(const sp<U>& other);
template<typename U> 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);
// promotion to 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;
// 指向他所引用的对象(继承自 RefBase)
T* m_ptr;
// 用来维护对象的弱引用计数
weakref_type* m_refs;
};
需要注意的是,弱指针与强指针有一个很大的区别,就是弱指针不可以直接操作他所引用的对象,因为他所引用的对象可能不受弱引用计数的控制,即它所引用的对象可能是一个无效的对象。因此如果需要操作一个弱指针引用的对象,那么就需要将这个弱指针升级为强指针,这是通过它的成员函数 promote 实现的。如果升级成功,那么就说明该弱指针所引用的对象还没有被销毁,可以正常使用。
wp 的实现比较复杂,重点是理解它的构造函数、析构函数意以及如何将一个弱指针升级为一个强指针。
首先分析它的构造函数。
wp 构造函数
源码位置:Android源码目录/system/core/include/utils/RefBase.h
template<typename T>
wp<T>::wp(T* other)
: m_ptr(other)
{
if (other) m_refs = other->createWeak(this);
}
实际上是调用 RefBase 的成员函数 createWeak 来增加对象的弱引用计数,代码如下:
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
mRefs->incWeak(id);
return mRefs;
}
RefBase 的成员变量 mRefs 指向 weakref_impl 对象,它的成员方法 incWeak 就是增加实际引用对象的弱引用计数,最后将 mRefs 返回。
wp 析构函数
源码位置:Android源码目录/system/core/include/utils/RefBase.h
template<typename T>
wp<T>::~wp()
{
if (m_ptr) m_refs->decWeak(this);
}
就是调用 它的成员变量 m_refs 的成员函数 decWeak 来减少弱引用计数。m_refs指向的是一个 weakref_impl 对象,因此这里实际上会调用 weakref_impl 的成员函数 decWeak 来减少对象的弱引用计数。
接下来重点分析 wp 的成员函数 promote,该函数用来将一个弱指针升级为一个强指针。前面介绍到弱引用不能直接操作它引用的对象,那么这是如何实现的呢?
- wp 没有重载 “*” 和 “->”操作符,因此,我们就不能直接操作它所引用的对象。
wp 的成员函数 promote 实现如下:
template<typename T>
sp<T> wp<T>::promote() const
{
sp<T> result;
if (m_ptr && m_refs->attemptIncStrong(&result)) {
result.set_pointer(m_ptr);
}
return result;
}
m_ptr 指向对象的地址,m_refs 指向该对象内部的一个弱引用计数器。只有在对象地址不为NULL的情况下,才会调用它内部的弱引用计数器对象的成员函数 attemptIncStrong 来试图增加该对象的强引用计数。如果能够成功增加强引用计数,那么就可以成功地把一个弱指针升级为一个强指针。m_refs是一个类型为 weakref_type 的指针,因此接下来就会调用 weakref_type 的成员函数attemptIncStrong,其实现如下:
bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
incWeak(id);
weakref_impl* const impl = static_cast<weakref_impl*>(this);
int32_t curCount = impl->mStrong.load(std::memory_order_relaxed);
ALOG_ASSERT(curCount >= 0,
"attemptIncStrong called on %p after underflow", this);
while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
std::memory_order_relaxed)) {
break;
}
}
if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
if (curCount <= 0) {
decWeak(id);
return false;
}
while (curCount > 0) {
if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
std::memory_order_relaxed)) {
break;
}
}
if (curCount <= 0) {
decWeak(id);
return false;
}
} else {
if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
decWeak(id);
return false;
}
curCount = impl->mStrong.fetch_add(1, std::memory_order_relaxed);
if (curCount != 0 && curCount != INITIAL_STRONG_VALUE) {
impl->mBase->onLastStrongRef(id);
}
}
}
impl->addStrongRef(id);
#if PRINT_REFS
ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
#endif
if (curCount == INITIAL_STRONG_VALUE) {
impl->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
std::memory_order_relaxed);
}
return true;
}
weakref_type 的成员函数 attemptIncStrong 试图增加目标对象的强引用计数器,但是可能会增加失败(目标对象已经被释放,或者该目标对象不允许使用强指针引用它)。
在增加强引用计数的同时也会增加弱引用计数,因此以上函数首先调用 incWeak 来增加弱引用计数。wp 的成员变量 m_refs 指向的是一个 weakref_impl 对象,接下来可以安全地将 this 指针
转化为 weakref_impl 指针,并保存在 impl 中。
一个弱指针引用的对象可能处于两种状态:
- 该对象正被其他强指针引用,因此它的强引用计数值大于 0,并且不等于 INITIAL_STRONG_VALUE;
- 该对象没用被任何强者针引用,即它的强引用计数值小于等于 0,或是等于 INITIAL_STRONG_VALUE。
先分析第一种情形,由于它的强引用计数值大于 0,也就是说这时候对象一定是存在的,因此可以安全的将弱指针升级为强指针,并将对象的强引用计数加 1。
while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
// we're in the easy/common case of promoting a weak-reference
// from an existing strong reference.
if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
std::memory_order_relaxed)) {
break;
}
}
compare_exchange_weak 可以保证原子性,也会出现增加强引用计数失败的情况,在调用函数 compare_exchange_weak 前,其他线程正在修改 curCount 的值就会造成这种情况,通过 while 循环来重新执行该操作。
第二种情况比较复杂,此时对象可能存在也可能不存在,要进一步判断。
-
如果 (flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG 为 true,也就是说该对象生命周期只受强引用计数控制。
- 如果 curCount <= 0 也就是说该对象不存在,那么减少之前增加的弱引用计数,并返回 false;
- 如果 curCount > 0,实际上就是 curCount == INITIAL_STRONG_VALUE,此时由于该对象生命周期只受强引用计数控制,而此时该对象又没有被任何强指针引用过,那么它必然不会被释放,此时可以安全的将其升级为强指针。
如果该对象的生命周期受弱引用计数影响,那么就说明该对象肯定是存在的,因为现在正有一个弱指针在引用该对象。但是还要进一步调用函数 onIncStrongAttempted 来确认对象是否允许强指针引用它。如果为 true,那么就可以成功升级为强指针。
onIncStrongAttempted 实现如下:
bool RefBase::onIncStrongAttempted(uint32_t flags, const void* /*id*/)
{
return (flags&FIRST_INC_STRONG) ? true : false;
}
RefBase 类的成员函数在参数 flags 为 FIRST_INC_STRONG 的情况下允许将一个指向只受弱引用计数影响生命周期的对象的弱指针升级为强指针。
到这里关于只能指针的相关内容的分析就基本完成了,希望对你有帮助。
参考文献: