android中的智能指针

来源:互联网 发布:数控机床如何编程 编辑:程序博客网 时间:2024/05/16 15:55

    本文参考了<<深入理解Android卷I>>第五章,感谢作者!

    智能指针主要用来解决多个指针指向同一对象时,一个指针被销毁时删除了对象导致的指针悬挂问题.  

    智能指针的实现原理:使用引用计数来管理指向对像的拷贝,智能指针将一个计数器和指向的对像关联起来,在创建智能指针时将计数器初始化为1(使用指向的对像来创建),使用其他智能指针进行创建时将调用拷贝构造函数,拷贝构造函数将计数器加1,对其他智能指针赋值时减少左值的计数值增加右值的计数值,释放指针将调用析构函数,析构函数中减少计数器的值.在任何情况下,减少计数器的值后,检查计数值是否为0,如果为0就删除指向对像.  

    为了看得清楚些,忽略o和o2的指针悬挂问题..

   

   Object o=new Object();  SmartPtr p1(o);  // --->初始化o的计数值C(o)=1  SmartPtr p2(p1);  //--->调用拷贝构造函数,C(o)加1 , C(o)==2  Object o2=new Object();   SmartPtr p3(o2);// C(o2)=1  p3=p1;// 减少C(o2),增加C(o), 则:C(o2)==0,删除对像o2,C(o)==3  delete p1; // C(o)减1, C(o)==2  delete p2;// C(o)减1 ,C(o)==1  delete p3;// C(o)减1,C(o)==0,删除对像o.</span>

    智能指针是C++中概念,Android中有类似的东西,用来控制对像的生命周期,以便用于内存自动回收.Android使用refBase来管理计数值,sp,wp来管理智能指针,通过这样的机制控制对像的生命周期.

1.refBase:  

    refBase有两个内部类weakref_type和weakref_impl,refBase把weakref_type指定为友元,同时包含了一个指向weakref_impl对像的指针mRefs.  

    创建refBase对像时,其实创建了两个对像,一个是refBase自身,一个是weakref_impl对像,weakref_impl对像就是用来管理refBase自身对像(可以称为真实对像)的.

    weakref_impl继承weakref_type,包含了一个指向RefBase对像的指针mBase.  

    weakref_impl中成员:


   volatile int32_t    mStrong; //强引用计数  volatile int32_t    mWeak; //弱引用计数  RefBase* const      mBase; //用来指向真实对像  volatile int32_t    mFlags;//用来指定真实对像生命周期管理方式</span>
    包含了一组什么也没干的函数:(注意这是release版本,调试版本不是空的,因此这组函数其实是用于调试用的,在分析时可以忽略)
<span style="font-size:18px;">  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) { }</span>

构造函数
RefBase::RefBase()    : mRefs(new weakref_impl(this)) //在初始化时创建了weakref_impl对像赋值给mRefs{}weakref_impl(RefBase* base)        : mStrong(INITIAL_STRONG_VALUE) //强引用计数初始化为INITIAL_STRONG_VALUE        , mWeak(0)//弱引用计数初始化为0        , mBase(base)//指向真实对像,上面传入的this指针        , mFlags(0)//强引用计数管理生命周期    {    }


析构函数,当真实对像被析构时调用

RefBase::~RefBase(){    if (mRefs->mStrong == INITIAL_STRONG_VALUE) {        delete mRefs;//强引用计数是初始化值,那么删除weakref_impl对像    } else {        if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {//对像采用弱引用生命周期            if (mRefs->mWeak == 0) {                delete mRefs;//检查弱引用计数值,如果为0就删除weakref_impl对像            }    }  }  const_cast<weakref_impl*&>(mRefs) = NULL;}

在析构函数中,检查强引用计数是否为初始值,如果是就删除weakref_impl对像,为什么这样的做呢?因为如果强引用计数为初始值,说明这次析构一定是由弱引用计数值为0引发的!如果强引用计数不为初始值,那么说明析构可能是因为强引用计数减至0引发也可能由弱引用计数减至0引发,检查对像生命周期管理方式是否为弱引用计数管理,如果是那么再检查弱引用计数,如果弱引用计数为0,则删除weakref_impl对像.


增加弱引用计数.

void RefBase::weakref_type::incWeak(const void* id){    weakref_impl* const impl = static_cast<weakref_impl*>(this);    impl->addWeakRef(id);//什么也不做    const int32_t c = android_atomic_inc(&impl->mWeak);//弱引用计数加1    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);}

调用incWeak仅增加弱引用计数.


减少弱引用计数

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);//弱引用减1,返回旧值    ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);    if (c != 1) return;//旧的弱引用值不为1,说明弱引用计数不为0,则返回//此时弱引用计数为0,需要删除weakref_impl对像    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {//采用强引用计数管理生命周期        if (impl->mStrong == INITIAL_STRONG_VALUE) {            //强引用计数值为初始化值,而弱引用计数值已经变成0了,因此需要删除对像            delete impl->mBase;//删除真实对像,会引发对像的析构函数,析构函数中会删除weakref_impl对像.        } else {            // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);            delete impl;//强引用计数不是初始值,那么直接删除weakref_impl对像,而不要删除真实对像,因为它采用强引用计数生命周期管理        }    } else {        //使用弱引用计数管理生命周期        impl->mBase->onLastWeakRef(id);        if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {            delete impl->mBase;//删除真实对像,会引发对像的析构函数,析构函数中会删除weakref_impl对像        }    }}

调用decWeak减少弱引用计数,如果弱引用计数减至0,那么需要考虑删除真实对像和weakref_impl对像了:   对像采用强引用计数管理生命周期:  1.1强引用计数还是初始值,没有人使用,那么需要删除真实对像,删除真实对像会引发析构函数,从而删除weakref_impl对像.  1.2 强引用计数不是初始值,被使用过了,那么只需要删除weakref_impl对像.  对像采用弱引用计数管理生命周期:删除真实对像,在引发的析构函数中删除weakref_impl对像.因此decWeak将弱引用计数减至0时,除了对像使用强引用计数管理生命周期并且强引用计数被使用过的情况外,都会删除真实对像,在任何情况下都会删除weakref_impl对像.


增加强引用计数

void RefBase::incStrong(const void* id) const{    weakref_impl* const refs = mRefs;    refs->incWeak(id);//弱引用计数加1    refs->addStrongRef(id);    const int32_t c = android_atomic_inc(&refs->mStrong);//强引用计数加1,并返回旧值    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);//强引用计数-INITIAL_STRONG_VALUE,强引用计数现在等于1    refs->mBase->onFirstRef();//refBase的继承者可以覆盖此函数,在第一次引用时来做一些初始化操作}

调用incStrong,会同时增加强引用计数和弱引用计数


减少强引用计数:

void RefBase::decStrong(const void* id) const{    weakref_impl* const refs = mRefs;    refs->removeStrongRef(id);    const int32_t c = android_atomic_dec(&refs->mStrong);//强引用计数减1,并返回旧值#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) {//此处强引用计数为0        refs->mBase->onLastStrongRef(id);//引用值为0了,调用onLastStrongRef        if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {            delete this;//如果是强引用计数生命周期管理方式,删除此对像        }    }    refs->decWeak(id);//弱引用减1}

调用decStrong会同时减少强引用计数和弱引用计数,而且如果强引用计数减少到0并且对像采用强引用计数管理生命周期的话需要删除真实对像.


设置对像的生命周期:

 enum {        OBJECT_LIFETIME_STRONG  = 0x0000,//使用强引用计数管理生命周期        OBJECT_LIFETIME_WEAK    = 0x0001,//使用弱引用计数管理        OBJECT_LIFETIME_MASK    = 0x0001    };void RefBase::extendObjectLifetime(int32_t mode){    android_atomic_or(mode, &mRefs->mFlags);}

总结:对像生命周期管理方式为强引用计数管理时,当强引用计数减至0,对像一定会被删除,但是它的weakref_impl对像不一定被删除,当弱引用计数减至0时weakref_impl对像一定会被删除,但是对像不一定被删除.对像生命周期为弱引用计数管理时,当强引用计数减至0,对像和weakref_impl对像都不会被删除,当弱引用计数减至0时,对像会被删除,然后weakref_impl对像会在析构函数中被删除.


尝试增加强引用计数

bool RefBase::weakref_type::attemptIncStrong(const void* id){    incWeak(id);    weakref_impl* const impl = static_cast<weakref_impl*>(this);    int32_t curCount = impl->mStrong;  //尝试增加强引用计数,如果增加成功或者强引用计数为初始值或者强引用计数被减至0,跳出循环    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {        if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {            break;        }        curCount = impl->mStrong;    }        if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {        bool allow;        if (curCount == INITIAL_STRONG_VALUE) {            //强引用计数为初始值,采用强引用计数管理生命周期时允许增加强引用计数            allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK                  || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);        } else {            //强引用计数变成0了,采用弱引用计数管理生命周期时允许增加强引用计数,因此只有此种情况对像还存在世上.            allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK                  && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);        }        if (!allow) {            decWeak(id);//不允许时,减少开始增加的弱引用计数            return false;        }        curCount = android_atomic_inc(&impl->mStrong);//增加强引用计数,返回旧值        if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {            impl->mBase->onLastStrongRef(id);//什么也没做        }    }    impl->addStrongRef(id);    if (curCount == INITIAL_STRONG_VALUE) {        android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);        impl->mBase->onFirstRef();    }    return true;}


尝试增加弱引用计数:

bool RefBase::weakref_type::attemptIncWeak(const void* id){    weakref_impl* const impl = static_cast<weakref_impl*>(this);    int32_t curCount = impl->mWeak;    while (curCount > 0) {        if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {            break;        }        curCount = impl->mWeak;    }    if (curCount > 0) {        impl->addWeakRef(id);    }    return curCount > 0;//当前弱引用计数为0时代表weakref_impl对像已释放,所以增加弱引用计数会失败}</span>


2.sp,wp  

    refBase用来管理对像的计数值,而sp用来创建对像的强指针,wp用来创建弱指针.创建sp时会调用incStrong,析构sp时会调用decStrong,创建wp时会调用createWeak或incWeak,析构wp时会调用decWeak.sp和wp都会重载操作符=,依据智能指针的原理管理计数值.  

    sp和wp的互相转换:sp->wp直接通过wp的构造函数,wp->sp通过wp的promote函数.


0 0
原创粉丝点击