长久以来,C++中的内存管理问题一直让人头疼,空指针,野指针,内存泄露。。。。。。C++程序员看到这样的问题就是各种头大!这样的问题往往很难解决,尤其是代码架构比较庞大或者复杂的时候。但是同样是面向对象的JAVA语言却没有这个问题,为什么呢?因为java有GC,也就是垃圾回收而C++没有。C++的做法是:程序员必须做到在new一个对象之后当不需要使用它的时候必须delete这个对象。看来很好,没有问题是吧?但是,在实际的项目中,就是会有人忘记去delete这个对象,或者随意delete一个对象,导致依赖这个对象的别的模块发生野指针错误。这几乎是经常发生的,而且是很难避免的。
Android中除了framework之上是Java语言写就的,其余native层到kernel之上这部分基本都是C++写成的。Android的这部分代码量还是比较庞大的,那么它是怎么解决上面提到的C++内存问题的呢?为此,android引入了一个”智能指针“的概念,其实这个概念并不是android提出的,这个概念在C++的boost中就有的,google只是拿过来做了一个精简版本罢了。对C++ boost的智能指针感兴趣的可以看这个博客:
http://blog.csdn.net/xt_xiaotian/article/details/5714477
这里我们专注了解android中的智能指针是怎么实现的。Android的智能指针其实是比较复杂的,一时半会也说不清楚,在正式分析android的智能指针代码之前,我们继续上面的C++内存问题探讨。
前面提到,在C++中需要new和delete配对使用,而且是程序员手动显式执行。这对于程序员的要求是很高的,程序员需要知道什么时候new了一个对象,什么时候这个对象肯定是不需要的了然后采取delete它。这似乎有些理想,因为很多情况下不是这样的,有的时候我们new一个对象然后这个对象就是给别的模块使用的,别的模块又是由别的小组或者公司维护的,他们很可能不会及时delete这个对象。那有什么办法可以解决这个问题呢?我们很容易会想到,专门造一个模块,这个模块来关于众多产生的对象,然后同时负责这些对象的销毁。但是,这个方案有一个问题,如果需要产生多个管理模块的情况下,怎么保证多个模块之间的引用是一致的呢?也就是说可能管理模块A持有某个对象的引用,然后某块B也持有这个对象的引用,这样的话这两个模块之间怎么协调这个对象的引用问题呢?这是比较复杂的,也会有很多潜在的问题。那还有什么办法呢?要解决这个问题需要理解一个事情,那就是对象的引用计数问题,这是java的GC实现的基础。所谓引用计数就是这个对象在几个地方被使用了,比如:
Object a = new Object();
Object b = a;
这两行代码中,新new出来的对象有两个引用计数,引用a和引用b同时指向同一块内存空间。那什么时候我们就不需要这个对象了呢?那就是他不需要的时候?这有点像废话,但是事实就是这样,只要当这个对象的引用计数等于0的时候,这个对象就不需要了。这样以来,这个问题就转化为:找到谁对这个对象的引用技术最为清楚?谁最直接了解这个对象的引用计数?对了!答案就是这个对象它自己!!!什么?你要这个对象自己delete自己,听起来有点荒谬,但是android中的智能指针就是这么做的。
LightRefBase
这是个android中给出的一个轻量级的智能指针解决方案,使用的思想就是我们上面分析的思想。为了让对象可以做到自己delete自己,我们需要给所有的对象做一个公共的基类,这个LightRefBase就是这个基类。在分析这个代码之前,我们先看一下,这个东西我们怎么使用,以下是一个使用它的demo:
/*************************************************************************
> File Name: lightpointer.cpp
> Author: Baniel Gao
> Mail: [email protected]
> Created Time: Fri 22 Apr 2016 03:27:28 PM CST
************************************************************************/
#include <stdio.h>
// 包含需要的头文件
#include <utils/RefBase.h>
using namespace android;
// 目标类必须是LightRefBase的子类
class LightClass : public LightRefBase<LightClass>
{
public:
LightClass()
{
printf("create instance of lightclass. \n");
}
virtual ~LightClass()
{
printf("destory instance of lightclass. \n");
}
};
int main(int argc, char** argv)
{
// new一个对象,并且将指针指向它
LightClass* ptr = new LightClass();
// 打印引用计数,就是看看有多少个地方使用了它,当然这里还没有显式引用,结果应该是0.
printf("1. Light ref count: %d. \n", ptr->getStrongCount());
// sp<>这样的引用就是显式引用,是的一个指针指向它,然后我们看下现在的引用计数是多少
// 按照推理,应该是1.
sp<LightClass> ptrOut = ptr;
printf("2. Light ref count: %d. \n", ptr->getStrongCount());
// 代码块,在代码块内部再弄一个指针指向这个对象,然后再看一下引用计数
{
sp<LightClass> ptrInner = ptr;
printf("3. Light ref count: %d. \n", ptr->getStrongCount());
}
// 再代码块的外面,我们看一下引用计数。由于在代码块的外面,代码块的内部的那个
// 指向指针应该不存在了,所有引用计数应该比代码块内部少一个。
printf("4. Light ref count: %d. \n", ptr->getStrongCount());
// 将最后一个引用置空, 并且睡眠两秒,等待看看这个对象会不会自动销毁。
ptrOut = NULL;
printf("5. Light ref count: %d. \n", ptr->getStrongCount());
printf("Wre are going to sleep. \n");
sleep(2)
// 2s后我们直接退出程序
printf("Wre are going to exit. \n");
return 0;
}
大家先不用管具体的代码细节是怎么回事,先看看运行的结果。为了运行这个程序我们需要编译它,这里我把它编译成android手机上可以运行的二进制文件,下面是Android.mk文件:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := lightpointer
LOCAL_SRC_FILES := lightpointer.cpp
LOCAL_SHARED_LIBRAIES := libcutils libutils
include $(BUILD_EXECUTABLE)
可执行文件名称就是lightpointer,并且存放于手机的system/bin下,以下是运行效果:
可以看到和我们的猜想是基本一致的。首先,我们new一个对象,但是没有显式引用所以引用计数当然是0,然后我们使用sp类(这个类先不去理会稍后分析)引用它,然后它的计数就是1了,再然后再代码块中再次引用它,发现计数是2,然后在代码块的外部发现对象引用计数还是1,因为代码块执行完毕了,刚才内部的那个指针不存在了。最后我们再把最后一个指针置空,然后这个对象由于引用计数为0了就自动销毁了。看到了没有,是不是有点JAVA的意思啊?使用很简单是不?
现在我们来分析一下刚才代码再android系统内发生了什么,首先我们看一下LightRefBase这个类,代码路径:/system/core/include/utils/RefBase.h
它的代码如下
我们看到,这个类的实现还是比较简答的,整体上公共方法就3个:
incStrong
decStrong
getStrongCount //刚才我们一直在用的方法
我们所有的目标类都应该是它的子类,首先我们应该看一下它的构造器。它的构造器是比较简单的,只是将mCount这个变量初始化为0,从字面意思我们也可以看出这个变量就是表示实际的引用数目。并且我们刚才一直使用的getStrongCount方法也就是把它直接return了。接下来我们看到incStrong和decStrong两个方法,从字面上可以看出来,这两个方法分别是增加引用计数和减少引用计数。我们先看一下增加引用技术吧,他做的事情比较简单,直接使用android的util函数库中的android_atomic_inc来将mCount变量加1,这个函数的加1操作是原子操作,从名字上也可以看出,这是为了线程安全考虑的。然后我们再看一下减少引用技术的操作,这个也很简单,首先使用android_atomic_dec这个原子操作函数将mCount减1,然后根据这个函数的返回值判断是不是最后一个引用计数,如果是就直接delete这个对象,如果不是就跳过。这里需要说明一下,android_atomic_dec这个函数的返回值是mCount减少之前的值相当于mCount–的值,所以这里判断的条件是1而不是0。但是现在我们有一个问题这些增加和减少引用计数的方法是哪里调用的呢?还记得我们在上面那个代码中的sp类吗?对,就是它调用的!我们来看一下它的代码:
它的代码路径:/system/core/include/utils/StrongPointer.h,代码内容如下:
可以看到,它的内部方法基本很少,大部分都是运算符的重载。我们先看一下它的构造器:
首先,这个类是一个模板类,具体的对象类型是一个泛型。我们可以看到在它的构造器中将目标对象的引用赋值给m_ptr指针,然后如果目标对象的指针不为空的话直接调用它的incStrong方法将引用计数值加1。这是使用构造器传递指针的方式进行初始化的方式,我们上面的代码并没有使用这个方式,我们使用的是它的=号运算符重载:
可以看到这里才是我们上面代码使用的地方,这里和构造器逻辑基本类似,也是直接调用incStrong方法将引用加1。这里需要说明一下,这个方法考虑了sp指针重新赋值的情况,也就是说如果原本的m_ptr不为空,即原本是有指向的,现在需要先减少目标对象的引用计数,然后再将新的指针赋值给它。也就是说只要我们执行这条代码:
sp<LightClass> ptrOut = ptr;
就会执行上面的代码,然后引用计数就加1。相反如果我们把指针赋值为NULL或者别的值那么目标对象的引用计数就会减少。
这样一来,目标对象只要继承自LightRefBase类,并且我们使用sp类指针对引用就能实现对象的自动销毁,而不用再手动地执行delete了。
以上就是LightRefBase的分析,这是android的轻量级智能指针方案,实现和使用都比较简单,代码清爽不繁杂,这也就是他为什么叫轻量级的原因。
RefBase
如果说上面的LightRefBase是轻量级的,那么RefBase就应该是重量级的了,它的名字中少了light。Android为神马要引入这个类呢?想一下这样一个场景,现在有两个对象:A和B,对象A中有B的引用,因此B的引用等于1;对象B中有A的引用,因此对象A的引用对于1;现在问题来了,这两个对象和外界的任何对象都没有关系,也就说除了A和B两者之间有关系,别人和他们都没有关系!现在他们就是多余的了,应该被销毁!但是由于A和B的引用计数都是1,不为0,因此使用我们上面的方案解决不了了!还是会有内存泄露问题!怎么办呢??解决的办法是这样的,将引用分类,分为两类:强引用和弱引用。强引用就是我们上面使用的那种,弱引用是什么呢?弱引用从字面上引用的力度比强引用要弱,事实确实是这样。弱引用弱在哪里呢?弱在保证使用对象的可靠性上。这么说有点抽象,具体来说吧,像上面说的那个问题,如果A对象对B对象的引用是强引用的话,那么B对象对A对象必须是弱引用,否则还有刚才说的循环引用的问题。对象的销毁,关注的是对象的强引用,而不是对象的弱引用,也就是说如果对象的强引用为0的话不管对象的弱引用是多少直接delete掉!这就是弱引用弱的地方,也就是说你想使用的对象不一定存在呢!!另外,还有一个问题,那就是既然对象可能不存了,弱引用怎么使用这个对象呢?面对这个问题,有这样一个规定:
1. 弱引用在使用之前不如先升级为强引用才行。
如果对象不存在了,那么升级弱引用是失败的,自然就可以避免引用对象存在不确定性的问题了。说了这么多,我们现在来分析一下RefBase的代码,它的代码和LightRefBase类存在于一个文件中: /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;
};
这个看起来有些复杂,下面我们来一步一步分析它的实现。首先他和LightRefBase一样,只是实现的功能不一样而已,都是目标类的基类,你的目标类必须是这个类的子类。接下来我们以强指针和弱指针为两条线路分析一下。
sp(强指针)
很多人刚开始看到sp的时候,都会以为sp是smart pointer的缩写,其实不是他是strong pointer的缩写。sp类的实现我们在前面分析LightRefBase类的时候已经分析过了,它的代码还是比较简单,主要就是一些运算符的重载。这里我们重点分析一下RefBase和sp的协作。前面提到,sp类是一个模板类,它的目标类型可以是任何类,也就是说可以是LightRefBase类的子类,当然也可以是RefBase类的子类。我们看到RefBase类提供的方法比较多,我们先看下RefBase类也提供了incStrong和decStrong方法,并且还有getStrongCount调试方法这个和LightRefBase是一样的。因此,在强指针这块,LightRefBase和RefBase差别不是很大。
wp(弱指针)
弱指针的实现才是重头戏,毕竟弱指针的提出就是为了解决上面提到的循环引用的问题。在进一步分析RefBase之前,我们先看一下wp也就是弱指针的实现。弱指针的实现在:/system/core/include/utils/RefBase.h文件中:
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;
T* m_ptr;
weakref_type* m_refs;
};
和强指针一样,wp也是一个模板类,因为目标类的类型是不确定的。我们看到wp类提供的方法也不是很多,很多都是一些运算符的重载。我们先看一下构造器的实现:
template<typename T>
wp<T>::wp(T* other)
: m_ptr(other)
{
if (other) m_refs = other->createWeak(this);
}
构造器中我们看到直接将目标对象的指针赋值给了m_ptr,然后就调用RefBase的createWeak方法:
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
mRefs->incWeak(id);
return mRefs;
}
这个方法直接调用weakref_type类对象的incWeak方法增加一个弱引用计数,那么weakref_type类是什么呢?我们可以看到RefBase类中提供了这个类,它是一个内部类:
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);
};
这个类是实际表示引用计数的类,为什么这么说呢?我们看以下RefBase类的实现就知道了,RefBase的实现代码:system/core/libutils/RefBase.cpp,这个代码中有一个叫做weakref_impl的内部类:
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 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
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)
{
}
~weakref_impl()
{
bool dumpStack = false;
if (!mRetain && mStrongRefs != NULL) {
dumpStack = true;
ALOGE("Strong references remain:");
ref_entry* refs = mStrongRefs;
while (refs) {
char inc = refs->ref >= 0 ? ‘+‘ : ‘-‘;
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
refs->stack.log(LOG_TAG);
#endif
refs = refs->next;
}
}
if (!mRetain && mWeakRefs != NULL) {
dumpStack = true;
ALOGE("Weak references remain!");
ref_entry* refs = mWeakRefs;
while (refs) {
char inc = refs->ref >= 0 ? ‘+‘ : ‘-‘;
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
refs->stack.log(LOG_TAG);
#endif
refs = refs->next;
}
}
if (dumpStack) {
ALOGE("above errors at:");
CallStack stack(LOG_TAG);
}
}
void addStrongRef(const void* id) {
//ALOGD_IF(mTrackEnabled,
// "addStrongRef: RefBase=%p, id=%p", mBase, id);
addRef(&mStrongRefs, id, mStrong);
}
void removeStrongRef(const void* id) {
//ALOGD_IF(mTrackEnabled,
// "removeStrongRef: RefBase=%p, id=%p", mBase, id);
if (!mRetain) {
removeRef(&mStrongRefs, id);
} else {
addRef(&mStrongRefs, id, -mStrong);
}
}
void renameStrongRefId(const void* old_id, const void* new_id) {
//ALOGD_IF(mTrackEnabled,
// "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
// mBase, old_id, new_id);
renameRefsId(mStrongRefs, old_id, new_id);
}
void addWeakRef(const void* id) {
addRef(&mWeakRefs, id, mWeak);
}
void removeWeakRef(const void* id) {
if (!mRetain) {
removeRef(&mWeakRefs, id);
} else {
addRef(&mWeakRefs, id, -mWeak);
}
}
void renameWeakRefId(const void* old_id, const void* new_id) {
renameRefsId(mWeakRefs, old_id, new_id);
}
void trackMe(bool track, bool retain)
{
mTrackEnabled = track;
mRetain = retain;
}
void printRefs() const
{
String8 text;
{
Mutex::Autolock _l(mMutex);
char buf[128];
sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
text.append(buf);
printRefsLocked(&text, mStrongRefs);
sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
text.append(buf);
printRefsLocked(&text, mWeakRefs);
}
{
char name[100];
snprintf(name, 100, DEBUG_REFS_CALLSTACK_PATH "/%p.stack", this);
int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
if (rc >= 0) {
write(rc, text.string(), text.length());
close(rc);
ALOGD("STACK TRACE for %p saved in %s", this, name);
}
else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
name, strerror(errno));
}
}
private:
struct ref_entry
{
ref_entry* next;
const void* id;
#if DEBUG_REFS_CALLSTACK_ENABLED
CallStack stack;
#endif
int32_t ref;
};
void addRef(ref_entry** refs, const void* id, int32_t mRef)
{
if (mTrackEnabled) {
AutoMutex _l(mMutex);
ref_entry* ref = new ref_entry;
// Reference count at the time of the snapshot, but before the
// update. Positive value means we increment, negative--we
// decrement the reference count.
ref->ref = mRef;
ref->id = id;
#if DEBUG_REFS_CALLSTACK_ENABLED
ref->stack.update(2);
#endif
ref->next = *refs;
*refs = ref;
}
}
void removeRef(ref_entry** refs, const void* id)
{
if (mTrackEnabled) {
AutoMutex _l(mMutex);
ref_entry* const head = *refs;
ref_entry* ref = head;
while (ref != NULL) {
if (ref->id == id) {
*refs = ref->next;
delete ref;
return;
}
refs = &ref->next;
ref = *refs;
}
ALOGE("RefBase: removing id %p on RefBase %p"
"(weakref_type %p) that doesn‘t exist!",
id, mBase, this);
ref = head;
while (ref) {
char inc = ref->ref >= 0 ? ‘+‘ : ‘-‘;
ALOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);
ref = ref->next;
}
CallStack stack(LOG_TAG);
}
}
void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
{
if (mTrackEnabled) {
AutoMutex _l(mMutex);
ref_entry* ref = r;
while (ref != NULL) {
if (ref->id == old_id) {
ref->id = new_id;
}
ref = ref->next;
}
}
}
void printRefsLocked(String8* out, const ref_entry* refs) const
{
char buf[128];
while (refs) {
char inc = refs->ref >= 0 ? ‘+‘ : ‘-‘;
sprintf(buf, "\t%c ID %p (ref %d):\n",
inc, refs->id, refs->ref);
out->append(buf);
#if DEBUG_REFS_CALLSTACK_ENABLED
out->append(refs->stack.toString("\t\t"));
#else
out->append("\t\t(call stacks disabled)");
#endif
refs = refs->next;
}
}
mutable Mutex mMutex;
ref_entry* mStrongRefs;
ref_entry* mWeakRefs;
bool mTrackEnabled;
// Collect stack traces on addref and removeref, instead of deleting the stack references
// on removeref that match the address ones.
bool mRetain;
#endif
};
这个类的代码有点长,其实我们仔细看一下大部分都是DEBUG_REFS等宏控制的调试代码,我们分析的时候可以直接跳过,除了这些代码剩下的基本就是这些了:
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
volatile int32_t mStrong;
volatile int32_t mWeak;
RefBase* const mBase;
volatile int32_t mFlags;
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) { }
}
很精简是吧?我们看到weakref_impl类是weakref_type类的子类,并且在release版本中那些调试函数的实现全部是空的,主要就是这个类中的几个成员变量需要我们关注:
volatile int32_t mStrong;
volatile int32_t mWeak;
RefBase* const mBase;
volatile int32_t mFlags;
从名称也可以看出来,第一个是强引用计数,第二个是弱引用计数,第三个是一个指向RefBase类的指针,这个指针实际指向的是目标类的对象,因为目标类是RefBase类的子类,第四个是标志位,这个标志位主要用来管理对象的生命周期的,这个后面会说明。其实这里的weakref_impl就相当于LightRefBase里面的mCount,只是我们这里的RefBase需要管理强指针和弱指针,一个变量肯定是不行的,所以这里需要一个类来表示才行。
现在看来,wp,RefBase,weakref_impl类的关系有点乱,不太好理解,我们看一下下面的图:
其中wp是操作的指针类,这个类中包含指向RefBase实际目标子类对象的指针和一个指向weakref_impl类对象的指针;RefBase类包含了一个指向weakref_impl类对象的一个指针,用来管理引用计数;weakref_impl类就是实际的计数器,这个里面也包含了RefBase类子类的对象指针,另外,它是weakref_type类的子类。这些关系,需要读者认真理解参悟之前给出的代码才能弄明白的,一言半语只能明白个大概。
接下来的重点就是弄明白这几个类是怎么实现计数管理的目标的。之前我们说到了createWeak这个方法,这个方法直接调用了weakref_type类的incWeak方法,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 = android_atomic_inc(&impl->mWeak);
ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
可以看到最终调用了android_atomic_inc这个原子操作函数将weakref_impl类对象的mWeak变量增加了1。到这里我们就明白了在构造器中是怎么实现弱引用计数的管理的了。现在我们再看一下=号运算符重载部分的操作:
template<typename T>
wp<T>& wp<T>::operator = (T* other)
{
weakref_type* newRefs =
other ? other->createWeak(this) : 0;
if (m_ptr) m_refs->decWeak(this);
m_ptr = other;
m_refs = newRefs;
return *this;
}
基本逻辑还是一样的,先看目标对象的指针是不是空,如果不是空就调用createWeak,然后如果m_ptr不为空的话,也就是先前有指向那就先decWeak,释放弱引用计数,然后在将目标对象指针和weakref_type对象指针赋值。这一点和强指针的操作是一样的。
这里我们就基本分析完了弱引用计数的管理过程,但是之前说到,弱指针想要使用目标对象的方法,就必须将弱指针升级为强指针。那么怎么升级呢?前面我们在看wp类的定义时不知道大家有没有注意到这个方法:
// promotion to sp
sp<T> promote() const;
是的,就是这个方法,从字面意思上看,这个方法就是将弱指针升级为强指针的方法。我们看一下这个方法的实现:
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;
}
可以看到这里的操作就是通过weakref_type类的attemptIncStrong方法来获得强指针应用,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;
ALOG_ASSERT(curCount >= 0,
"attemptIncStrong called on %p after underflow", this);
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 (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
break;
}
// the strong count has changed on us, we need to re-assert our
// situation.
curCount = impl->mStrong;
}
if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
// we‘re now in the harder case of either:
// - there never was a strong reference on us
// - or, all strong references have been released
if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
// this object has a "normal" life-time, i.e.: it gets destroyed
// when the last strong reference goes away
if (curCount <= 0) {
// the last strong-reference got released, the object cannot
// be revived.
decWeak(id);
return false;
}
// here, curCount == INITIAL_STRONG_VALUE, which means
// there never was a strong-reference, so we can try to
// promote this object; we need to do that atomically.
while (curCount > 0) {
if (android_atomic_cmpxchg(curCount, curCount + 1,
&impl->mStrong) == 0) {
break;
}
// the strong count has changed on us, we need to re-assert our
// situation (e.g.: another thread has inc/decStrong‘ed us)
curCount = impl->mStrong;
}
if (curCount <= 0) {
// promote() failed, some other thread destroyed us in the
// meantime (i.e.: strong count reached zero).
decWeak(id);
return false;
}
} else {
// this object has an "extended" life-time, i.e.: it can be
// revived from a weak-reference only.
// Ask the object‘s implementation if it agrees to be revived
if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
// it didn‘t so give-up.
decWeak(id);
return false;
}
// grab a strong-reference, which is always safe due to the
// extended life-time.
curCount = android_atomic_inc(&impl->mStrong);
}
// If the strong reference count has already been incremented by
// someone else, the implementor of onIncStrongAttempted() is holding
// an unneeded reference. So call onLastStrongRef() here to remove it.
// (No, this is not pretty.) Note that we MUST NOT do this if we
// are in fact acquiring the first reference.
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
// now we need to fix-up the count if it was INITIAL_STRONG_VALUE
// this must be done safely, i.e.: handle the case where several threads
// were here in attemptIncStrong().
curCount = impl->mStrong;
while (curCount >= INITIAL_STRONG_VALUE) {
ALOG_ASSERT(curCount > INITIAL_STRONG_VALUE,
"attemptIncStrong in %p underflowed to INITIAL_STRONG_VALUE",
this);
if (android_atomic_cmpxchg(curCount, curCount-INITIAL_STRONG_VALUE,
&impl->mStrong) == 0) {
break;
}
// the strong-count changed on us, we need to re-assert the situation,
// for e.g.: it‘s possible the fix-up happened in another thread.
curCount = impl->mStrong;
}
return true;
}
这个方法比较长,我们一步步来分析下。首先如果目前的强引用计数不为0,并且不等于INITIAL_STRONG_VALUE(这个值是强引用计数的初始化的值)的话,这个情况也就是正常情况下,说明这个时候目标对象已经存了一个强引用,这个时候我们就直接调用android_atomic_cmpxchg函数将mStrong变量增加1,android_atomic_cmpxchg这个函数的定义如下:
android_atomic_cmpxchg(oldValue, newValue, addr)
这个函数的功能就是当oldValue的值和addr地址中的值一样的时候,就将newValue的值赋值给addr地址中的变量。我们这个地方的调用的目的就是,如果这个时候mStrong的值和我们之前获得的curCount值一样的话,就吧mStrong的值增加1,然后返回0,否则非0.这一步就是将强引用的值增加1,因为我们需要升级为强引用了。接下来就是判断curCount也就是目标对象的强引用的值了,会检查这个值是不是小于等于0或者等于它的初始值,这里的意思是如果目标对象的强引用全部被释放了,或者压根就没有被任何人引用过的话,就执行判断里面的代码,这显然是一种少数情况。我们看一下他里面的代码(上面已经贴出,这里截取片段,以便分析):
if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
// we‘re now in the harder case of either:
// - there never was a strong reference on us
// - or, all strong references have been released
if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
// this object has a "normal" life-time, i.e.: it gets destroyed
// when the last strong reference goes away
if (curCount <= 0) {
// the last strong-reference got released, the object cannot
// be revived.
decWeak(id);
return false;
}
// here, curCount == INITIAL_STRONG_VALUE, which means
// there never was a strong-reference, so we can try to
// promote this object; we need to do that atomically.
while (curCount > 0) {
if (android_atomic_cmpxchg(curCount, curCount + 1,
&impl->mStrong) == 0) {
break;
}
// the strong count has changed on us, we need to re-assert our
// situation (e.g.: another thread has inc/decStrong‘ed us)
curCount = impl->mStrong;
}
if (curCount <= 0) {
// promote() failed, some other thread destroyed us in the
// meantime (i.e.: strong count reached zero).
decWeak(id);
return false;
}
} else {
// this object has an "extended" life-time, i.e.: it can be
// revived from a weak-reference only.
// Ask the object‘s implementation if it agrees to be revived
if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
// it didn‘t so give-up.
decWeak(id);
return false;
}
// grab a strong-reference, which is always safe due to the
// extended life-time.
curCount = android_atomic_inc(&impl->mStrong);
}
// If the strong reference count has already been incremented by
// someone else, the implementor of onIncStrongAttempted() is holding
// an unneeded reference. So call onLastStrongRef() here to remove it.
// (No, this is not pretty.) Note that we MUST NOT do this if we
// are in fact acquiring the first reference.
if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
impl->mBase->onLastStrongRef(id);
}
}
前面我们提到了目标对象的生命周期的事情,这里就要涉及到了。首先,我们看一下目标对象都有那些生命周期,生命周期定义如下(定义在RefBase类中):
//! Flags for extendObjectLifetime()
enum {
OBJECT_LIFETIME_STRONG = 0x0000,
OBJECT_LIFETIME_WEAK = 0x0001,
OBJECT_LIFETIME_MASK = 0x0001
};
从注释中我们也可以看出来,这些生命周期枚举变量其实是标示再mFlag变量中的,并且可以使用extendObjectLifetime方法设置的:
void extendObjectLifetime(int32_t mode);
这个方法就是用户可以手动设置目标对象的生命周期的。现在我们来解释一下生命周期的含义,为了说明它的含义我们看一下强引用和弱引用减少时的销毁对象的策略就明白了,先看一下强引用的减少方法:
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
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) {
refs->mBase->onLastStrongRef(id);
if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
delete this;
}
}
refs->decWeak(id);
}
这里我们看到首先是将强引用计数减少1,然后判断这是不是最后的一个引用,如果是的话,那就回调目标对象的onLastStrongRef方法,通知目前是最后一个强引用这个对象可能要被销毁了。然后就是判断它的生命周期标识是不是OBJECT_LIFETIME_STRONG,如果是就销毁,如果不是就跳过。我们再看一下弱引用的减少方法:
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);
ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
if (c != 1) return;
if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
// This is the regular lifetime case. The object is destroyed
// when the last strong reference goes away. Since weakref_impl
// outlive the object, it is not destroyed in the dtor, and
// we‘ll have to do it here.
if (impl->mStrong == 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 {
// less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
impl->mBase->onLastWeakRef(id);
if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
// this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
// is gone, we can destroy the object.
delete impl->mBase;
}
}
}
我们看到,基本逻辑还是先减少弱引用计数的值,然后判断是不是最后一个弱引用,如果是就继续下面的代码,如果不是就直接返回。我们看一下如果是最后一个引用的情况,判断的依据还是目标对象的生命周期标识,如果是OBJECT_LIFETIME_STRONG的话,还要判断目前强引用计数是不是初始值也就是是不是压根就没有人引用它,如果是就直接销毁这个对象,如果不是就销毁目前的计数器类,也就是weakref_impl类的对象,然后强引用技术自然会由于指向的类被销毁就减少1,对象销毁由强引用管理完成。这是对象的生命周期标识是OBJECT_LIFETIME_STRONG的情况,如果对象的生命周期标识是其他的话,我们看到上面定义的生命周期标识中只有两个,但是这里的注释中提到了FOREVER标识,其实我们看下面的代码知道了,下面直接判断对象的生命周期标识是不是OBJECT_LIFETIME_WEAK,如果是就直接销毁对象,如果不是就什么也不做了。其实这里不会有别的情况,因为google定义的OBJECT_LIFETIME_MASK之判断flag的第一位,是0就是strong,1就是weak!!但是奇怪的是这里的注释提到了OBJECT_LIFETIME_{WEAK|FOREVER}这两个标识位,个人认为这可能是google的代码注释有问题的地方,可能以前老的版本中有这个定义但是现在新的版本中没有了,但是这个标识为没有删除!!因为我在这里分析的代码是6.0.1的这个版本中确实没有OBJECT_LIFETIME_FOREVER标识的定义,但是我在2.2.3版本找到这个定义,同时也证实了我们上面的猜想,google确实应该把这里的注释修改一下,以免使人误会呀!!!!
解释了生命周期方法之后我们继续看上面弱指针升级的代码,这里我们看到:
if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
// this object has a "normal" life-time, i.e.: it gets destroyed
// when the last strong reference goes away
if (curCount <= 0) {
// the last strong-reference got released, the object cannot
// be revived.
decWeak(id);
return false;
}
// here, curCount == INITIAL_STRONG_VALUE, which means
// there never was a strong-reference, so we can try to
// promote this object; we need to do that atomically.
while (curCount > 0) {
if (android_atomic_cmpxchg(curCount, curCount + 1,
&impl->mStrong) == 0) {
break;
}
// the strong count has changed on us, we need to re-assert our
// situation (e.g.: another thread has inc/decStrong‘ed us)
curCount = impl->mStrong;
}
if (curCount <= 0) {
// promote() failed, some other thread destroyed us in the
// meantime (i.e.: strong count reached zero).
decWeak(id);
return false;
}
}
首先判断是不是OBJECT_LIFETIME_STRONG标识,如果是的话,那就先判断强引用技术是不是小于等于0,也就是是不是所有的强引用都全部释放了,如果是的话,就减少弱引用然后直接返回false表示升级失败。当强引用计数大于0的时候,我们就先增加强引用技术,使用的方法和前面一样。最后,我们还要看一下目标对象的引用计数是不是小于等于0,如果是就直接减少弱引用计数,然后返回false。最后为什么还要判断引用计数呢?这里的注释已经解释了,因为对象有可能会在多线程中使用,可能在我们操作的同时就有线程把最后一个强引用释放了,这个时候对象已经被销毁了,因此这里我们需要检查一些,保证线程安全。
如果目标对象的生命周期标识是其他的话,也就是说是OBJECT_LIFETIME_WEAK的话,我们就回调目标对象的onIncStrongAttempted方法请求是不是允许在这种情况下升级指针,如果返回true表示允许,如果返回false表示不允许。这个方法目标对象类可以实现也可以实现,如果不实现的话就使用父类的定义:
bool RefBase::onIncStrongAttempted(uint32_t flags, const void* /*id*/)
{
return (flags&FIRST_INC_STRONG) ? true : false;
}
可以看到父类的实现比较简单,如果给的flag参数是FIRST_INC_STRONG的话,也就是是第一次强升级引用的话,那就允许,正好我们上面传递进来的参数就是这个,所以这样的话,如果目标对象类没有实现这个方法的话,升级操作总是允许的!这点需要明白的。如果目标对象不想允许这个时候的操作,那就实现这个方法,并且根据flag返回false就好了。继续我们的分析,如果允许这个时候的升级那就将强引用增加1.
接下来我们判断目前的强引用计数是不是在0~INITIAL_STRONG_VALUE之间也就是正常值范围内,因为我们这里的大前提条件就是目标对象没有被人引用过,因此这里需要回调onLastStrongRef方法,通知目标对象。
接下来的代码就比较简单了:
impl->addStrongRef(id);
#if PRINT_REFS
ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
#endif
// now we need to fix-up the count if it was INITIAL_STRONG_VALUE
// this must be done safely, i.e.: handle the case where several threads
// were here in attemptIncStrong().
curCount = impl->mStrong;
while (curCount >= INITIAL_STRONG_VALUE) {
ALOG_ASSERT(curCount > INITIAL_STRONG_VALUE,
"attemptIncStrong in %p underflowed to INITIAL_STRONG_VALUE",
this);
if (android_atomic_cmpxchg(curCount, curCount-INITIAL_STRONG_VALUE,
&impl->mStrong) == 0) {
break;
}
// the strong-count changed on us, we need to re-assert the situation,
// for e.g.: it‘s possible the fix-up happened in another thread.
curCount = impl->mStrong;
}
return true;
首先我们把这个强引用指针添加到强引用中去,但是我们前面分析说,在release版本中addStrongRef方法实现是空的,因此这一步跳过,它是调试使用的。接下来,我们先获得最新的强引用计数,然后判断mStrong的值是不是比INITIAL_STRONG_VALUE要大,有人会问,怎么会比这个值大呢?他不是强引用的最大值吗?是的,这个值既是最大值也是初始值,我们再来仔细看一下强引用增加部分的代码:
void RefBase::incStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->incWeak(id);
refs->addStrongRef(id);
const int32_t c = android_atomic_inc(&refs->mStrong);
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;
}
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
refs->mBase->onFirstRef();
}
注意这里的操作,首先是:
const int32_t c = android_atomic_inc(&refs->mStrong);
如果是第一次引用,然后就是:
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
第一次执行之后强引用的值是在初始值的基础上增加了1,也就是说这个时候的值已经比INITIAL_STRONG_VALUE大了,然后才执行android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);给它减去初始值才是最后的1.但是麻烦的是这里的两个操作并不是原子的,也就是说可能被打断,因此我们的attemptIncStrong方法最后才需要做出那个看似奇怪的判断,其实google的注释部分已经解释了这个问题了,大家可以看一下。attemptIncStrong函数的最后就直接返回true表示升级成功。这个时候我们返回来看我们的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;
}
如果attemptIncStrong返回为true的话,就吧result这个sp中的目标对象指针设置成现有的对象指针,以便sp指针操作这个对象;如果attemptIncStrong返回false的话,那就不会设置这个对象指针,那就是说sp的对象操作会发生段错误!!你在操作之前一定要调用sp的get()方法判断是不是确实升级成功了,get()方法定义:
inline T* get() const
{
return m_ptr;
}
到这里为止,我们就分析完了弱指针的升级过程。
sp和wp的demo
这里我给出一个demo代码,展示一下sp,wp和RefBase怎么使用,首先看下代码:
/*************************************************************************
> File Name: strongpointer.cpp
> Author: Baniel Gao
> Mail: [email protected]
> Created Time: Wed 22 Jun 2016 09:04:38 AM CST
************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <utils/RefBase.h>
using namespace android;
class StrongClass : public RefBase
{
public:
StrongClass()
{
printf("create an instance of StrongClass. \n");
}
virtual ~StrongClass()
{
printf("destory an instance of StrongClass \n");
}
void onFirstRef()
{
printf("StrongClass onFirstRef \n");
}
void onLastStrongRef(const void* id)
{
printf("StrongClass onLastStrongRef \n");
}
bool onIncStrongAttempted(uint32_t flags, const void* id)
{
printf("StrongClass onIncStrongAttempted \n");
return true;
}
void onLastWeakRef(const void* id)
{
printf("StrongClass onLastWeakRef \n");
}
};
class WeakClass : public RefBase
{
public:
WeakClass()
{
// 设置生命周期标识位
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
printf("create an instance of WeakClass \n");
}
virtual ~WeakClass()
{
printf("destory an instance of WeakClass \n");
}
void onFirstRef()
{
printf("WeakClass onFirstRef \n");
}
void onLastStrongRef(const void* id)
{
printf("WeakClass onLastStrongRef \n");
}
bool onIncStrongAttempted(uint32_t flags, const void* id)
{
printf("WeakClass onIncStrongAttempted \n");
return true;
}
void onLastWeakRef(const void* id)
{
printf("WeakClass onLastWeakRef \n");
}
};
int main(int argc, char** argv)
{
printf("####################strong class test start#################### \n");
sp<StrongClass> sp_ptr_1 = new StrongClass();
sp<StrongClass> sp_ptr_2 = sp_ptr_1;
wp<StrongClass> wp_ptr_1 = sp_ptr_1;
wp<StrongClass> wp_ptr_2 = sp_ptr_1;
printf("1. strong class strong refs: %d \n", sp_ptr_1->getStrongCount());
printf("2. strong class weak refs: %d \n", wp_ptr_1.get_refs()->getWeakCount());
sp_ptr_2 = NULL;
printf("3. strong class strong refs: %d \n", sp_ptr_1->getStrongCount());
wp_ptr_2 = NULL;
printf("4. strong class weak refs: %d \n", wp_ptr_1.get_refs()->getWeakCount());
printf("5. strong class strong refs: %d \n", wp_ptr_1.promote()->getStrongCount());
printf("6. we are going to release all weak refs!! \n");
wp_ptr_1 = NULL;
printf("7. we are going to release all strong refs!! \n");
sp_ptr_1 = NULL;
printf("####################strong class test end#################### \n");
printf("####################weak class test start#################### \n");
sp<WeakClass> sp_ptr_3 = new WeakClass();
sp<WeakClass> sp_ptr_4 = sp_ptr_3;
wp<WeakClass> wp_ptr_3 = sp_ptr_3;
wp<WeakClass> wp_ptr_4 = sp_ptr_3;
printf("1. weak class strong refs: %d \n", sp_ptr_3->getStrongCount());
printf("2. weak class weak refs: %d \n", wp_ptr_3.get_refs()->getWeakCount());
sp_ptr_4 = NULL;
printf("3. weak class strong refs: %d \n", sp_ptr_3->getStrongCount());
wp_ptr_4 = NULL;
printf("4. weak class weak refs: %d \n", wp_ptr_3.get_refs()->getWeakCount());
printf("5. weak class strong refs: %d \n", wp_ptr_3.promote()->getStrongCount());
printf("6. we are going to release all strong refs!! \n");
sp_ptr_3 = NULL;
printf("7. we are going to release all weak refs!! \n");
wp_ptr_3 = NULL;
printf("####################weak class test end#################### \n");
return 0;
}
Android.mk如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := strongpointer
LOCAL_SRC_FILES := strongpointer.cpp
LOCAL_SHARED_LIBRARIES := libcutils libutils
include $(BUILD_EXECUTABLE)
上面程序的运行结果如下:
结果是完全符合我们预期的,这里我们看到在WeakClass中实现了释放全部强引用而对象不被销毁,直到所有的弱引用被释放之后才被销毁!!其余的结果,读者可以结合上面我们的讲解,自己分析一下上面程序的输出为什么是这样的。