Android强指针和弱指针

2023-09-13 08:05:23

基类RefBase

  Android中强指针和弱指针都要继承自RefBase类。
  值得注意得是,Refbase类中有内部类weakref_type,有一个类型为weakref_impl*的成员变量。weakref_impl类继承自Refbase类的内部类weakref_type。weakref_type内部也有一个RefBase*类型的成员mBase指向了对应的Refbase对象。weakref_type类使用mStrong记录强引用计数,使用mWeak记录弱引用计数,使用mFlags记录指针生命周期取决于什么。mStrong被初始化为INITIAL_STRONG_VALUE,在宏定义被定义为2的28次方,mWeak被初始化为0。强引用计数和弱引用计数决定了指针什么时候该被释放。其中,OBJECT_LIFETIME_STRONG(也就是默认初始化值)表示只受强引用计数影响,OBJECT_LIFETIME_WEAK表示同时受强引用计数和弱引用计数影响, OBJECT_LIFETIME_MASK是一个掩码值,后面会使用flag&OBJECT_LIFETIME_MASK的形式来获取flag的最低位数值。

/frameworks/rs/cpp/util/RefBase.h

enum {
        OBJECT_LIFETIME_STRONG  =0x0000,
        OBJECT_LIFETIME_WEAK    =0x0001,
        OBJECT_LIFETIME_MASK    =0x0001
    };

/frameworks/rs/cpp/util/RefBase.h

class RefBase
{public:voidincStrong(constvoid* id)const;void            decStrong(constvoid* id)const;void            forceIncStrong(constvoid* id)const;//! DEBUGGING ONLY: Get current strong ref count.
            int32_t         getStrongCount()const;

    class weakref_type
    {public:
        RefBase*refBase()const;void                incWeak(constvoid* id);void                decWeak(constvoid* id);// acquires a strong reference if there is already one.bool                attemptIncStrong(constvoid* 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(constvoid* 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(constvoid* id)const;

            weakref_type*   getWeakRefs()const;//! DEBUGGING ONLY: Print references held on object.
    inlinevoid            printRefs()const { getWeakRefs()->printRefs(); }//! DEBUGGING ONLY: Enable tracking of object.
    inlinevoid            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
    };virtualvoid            onFirstRef();virtualvoid            onLastStrongRef(constvoid* id);virtualbool            onIncStrongAttempted(uint32_t flags,constvoid* id);virtualvoid            onLastWeakRef(constvoid* id);private:
    friendclass ReferenceMover;staticvoid moveReferences(void* d,voidconst* s, size_t n,const ReferenceConverterBase& caster);private:
    friendclass weakref_type;
    class weakref_impl;

                            RefBase(const RefBase& o);
            RefBase&operator=(const RefBase& o);

        weakref_impl*const mRefs;
};

  RefBase的构造函数将this作为参数,new一个weakref_impl对象。

/frameworks/rs/cpp/util/RefBase.cpp

RefBase::RefBase()
    : mRefs(new weakref_impl(this))
{
}

  weakref_impl构造函数将传入的RefBase保存在mBase中。

/frameworks/rs/cpp/util/RefBase.cpp

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)
        , mStrongRefs(NULL)
        , mWeakRefs(NULL)
        , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
        , mRetain(false)
    {
    }...

  RefBase的析构函数被定义成虚函数,在析构时防止只析构基类不析构派生类的情况发生。
/frameworks/rs/cpp/util/RefBase.cpp

RefBase::~RefBase()
{if (mRefs->mStrong == INITIAL_STRONG_VALUE) {// we never acquired a strong (and/or weak) reference on this object.delete mRefs;
    }else {// life-time of this object is extended to WEAK or FOREVER, in// which case weakref_impl doesn't out-live the object and we// can free it now.if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {// It's possible that the weak count is not 0 if the object// re-acquired a weak reference in its destructorif (mRefs->mWeak ==0) {delete mRefs;
            }
        }
    }// for debugging purposes, clear this.const_cast<weakref_impl*&>(mRefs) = NULL;
}

强指针类sp

  sp类是一个模板类,模板参数必须继承自RefBase。sp类是对普通指针的封装,它内部有一个普通指针成员m_ptr,保存了这个普通指针,这个普通指针指向类型和模板参数相同。

/frameworks/rs/server/StrongPointer.h

template <typename T>class sp
{public:inline sp() : m_ptr(0) { }

    sp(T* other);
    sp(const sp<T>& other);template<typename U> sp(U* other);template<typename U> sp(const sp<U>& other);

    ~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);// Resetvoid clear();// Accessorsinline  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>friendclass sp;template<typename Y>friendclass wp;void set_pointer(T* ptr);
    T* m_ptr;
};

  先看看sp实例是如何构造出来的。sp类将模板类型的参数保存在成员m_ptr中,然后调用模板参数类的父类RefBase的incStrong函数。

/frameworks/rs/server/StrongPointer.h

template<typenameT>
sp<T>::sp(T* other)
: m_ptr(other)
  {if (other) other->incStrong(this);
  }

  sp的this作为RefBase::incStrong的id参数传入,方便调试用。首先,创建一个和mRefs指向相同的指针,调用RefBase::weakref_type::incWeak方法。incWeak方法中,虽然调用的是weakref_type的incWeak方法,但是调用者refs本质上是weakref_impl*类型,所以weakref_type*类型的指针可以被安全强转成weakref_impl*类型的指针,从而对weakref_impl内部mWeak弱引用计数加1。android_atomic_inc返回的是加1前的值。回到RefBase::incStrong方法,接下来对强引用计数加1。前面提到,强引用计数初始化时是INITIAL_STRONG_VALUE,加1后需要减去INITIAL_STRONG_VALUE恢复正确值。最后,调用RefBase的onFirstRef,这是个空实现,由子类去实现,可以加入一些首次被强指针引用时的逻辑。

/system/core/libutils/RefBase.cpp

void RefBase::incStrong(constvoid*id)const
{
    weakref_impl*const refs = mRefs;
    refs->incWeak(id);//debug方法
    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);#endifif (c != INITIAL_STRONG_VALUE)  {return;
    }

    android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
    refs->mBase->onFirstRef();
}

/system/core/libutils/RefBase.cpp

void RefBase::weakref_type::incWeak(constvoid* 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);
}

  可见,使用incStrong对强引用计数加1时,同时也会对弱引用计数加1。
  再看看sp的析构函数。可以看到是调用了RefBase的decStrong函数。

/frameworks/rs/server/StrongPointer.h

template<typename T>
sp<T>::~sp()
{if (m_ptr) m_ptr->decStrong(this);
}

  RefBase::decStrong方法中,使用android_atomic_dec对强引用计数减1,android_atomic_dec返回减1之前的值。如果此时强引用计数已变成0且指针生命周期仅取决于强引用计数,释放掉RefBase对象。最后,再对弱引用计数减1。可见,在使用decStrong对强引用计数减1的同时,也会对弱引用计数减1。

/frameworks/rs/cpp/util/RefBase.cpp

void RefBase::decStrong(constvoid*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) {
            deletethis;
        }
    }
    refs->decWeak(id);
}

  看看RefBase的析构函数。如果对象的强引用计数为初始化值,说明从未被强指针引用过,释放掉mRefs成员。如果曾经被强指针引用过,且生命周期不是仅取决于强引用计数,那么当弱引用计数为0时,释放掉mRefs成员。因为弱引用计数总是随着强引用计数增加或减少的,弱引用计数不会少于强引用计数,当弱引用计数为0时,强引用计数必然为0。

RefBase::~RefBase()
{if (mRefs->mStrong == INITIAL_STRONG_VALUE) {// we never acquired a strong (and/or weak) reference on this object.delete mRefs;
    }else {// life-time of this object is extended to WEAK or FOREVER, in// which case weakref_impl doesn't out-live the object and we// can free it now.if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {// It's possible that the weak count is not 0 if the object// re-acquired a weak reference in its destructorif (mRefs->mWeak ==0) {delete mRefs;
            }
        }
    }// for debugging purposes, clear this.const_cast<weakref_impl*&>(mRefs) = NULL;
}

弱指针类wp

  弱指针类wp和强指针类sp同样拥有被封装的指针成员m_ptr,还有一个weakref_type*类型的成员。

/frameworks/rs/cpp/util/RefBase.h

template <typename T>class wp
{public:typedeftypename 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);
    ...private:template<typename Y>friendclass sp;template<typename Y>friendclass wp;

    T*              m_ptr;
    weakref_type*   m_refs;
};

  看看wp的构造函数。

/frameworks/rs/cpp/util/RefBase.h

template<typenameT>
wp<T>::wp(T* other)
    : m_ptr(other)
{if (other) m_refs = other->createWeak(this);
}

/frameworks/rs/cpp/util/RefBase.h

template<typename T>
wp<T>::wp(const sp<T>& other)
    : m_ptr(other.m_ptr)
{if (m_ptr) {
        m_refs = m_ptr->createWeak(this);
    }
}

  createWeak调用RefBase::weakref_type::incWeak方法。

/frameworks/rs/cpp/util/RefBase.h

RefBase::weakref_type* RefBase::createWeak(constvoid*id)const
{
    mRefs->incWeak(id);return mRefs;
}

  incWeak函数对弱引用计数加1。

/frameworks/rs/cpp/util/RefBase.cpp

void RefBase::weakref_type::incWeak(constvoid* 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);
}

  可以发现,无论是在强指针中,还是在弱指针中,弱引用计数的数量都会大于或等于强引用计数的数量(排除未被强指针引用时强引用计数为INITIAL_STRONG_VALUE的情况)。
  看看wp的析构函数。

/frameworks/rs/cpp/util/RefBase.h

template<typename T>
wp<T>::~wp()
{if (m_ptr) m_refs->decWeak(this);
}

  decWeak函数中,首先会对弱引用计数减1。如果弱引用计数减1后不等于0,直接返回。若等于0,进入释放步骤。在释放步骤中,若对象的生命周期仅只受强引用计数影响且未被强指针引用过,释放掉对应的RefBase对象;若对象的生命周期只受强引用计数影响且曾被强指针引用过,此时因为弱引用计数为0,所以强引用计数也必定为0,只释放weakref_impl*指针,这里为什么不从RefBase开始释放呢?因为之前的decStrong函数已经释放过一次了。如果对象的生命周期同时受强引用计数和弱引用计数影响,释放掉对应的RefBase对象。

/frameworks/rs/cpp/util/RefBase.cpp

void RefBase::weakref_type::decWeak(constvoid* 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;
        }
    }
}

弱指针提升promote

  弱指针是不能直接操作引用对象的,必须提升成强指针才能操作引用对象。因为wp类没有重载*和->运算符。wp指针可以通过promote函数来提升为强指针。

/frameworks/rs/cpp/util/RefBase.h

template<typenameT>
sp<T> wp<T>::promote() const
{
    sp<T> result;if (m_ptr && m_refs->attemptIncStrong(&result)) {
        result.set_pointer(m_ptr);
    }return result;
}

  attemptIncStrong函数中,首先使用incWeak函数对弱引用计数加1。curCount记录为对象的强引用计数。当对象有被强指针引用时(curCount>0且不为初始值),使用android_atomic_cmpxchg对curCount加1,这里使用while循环,若加1失败则恢复原值重新执行加1操作。若对象从没被强指针引用过或者强引用计数小于或等于0,这里依据生命周期进行分情况讨论:1.如果对象生命周期仅受强引用计数影响,当curCount小于或等于0时,说明对象已被释放,没有提升的可能了,直接使用decWeak对弱引用计数减1,因为函数在开始的时候对弱引用计数加了1。当对象没被强指针引用过时,对curCount加1。在加1的循环体内,若其他线程使对象的强引用计数变成0,则说明对象会被释放,调用decWeak对弱引用计数减1。2.如果对象生命周期为其他方式,调用onIncStrongAttempted尝试对强引用计数加1,onIncStrongAttempted是RefBase的一个虚函数,有子类重写,具体功能是是否允许对强引用计数加1。若不允许,对弱引用计数减1;若允许,则对强引用计数加1。
  上述有些情况会导致强引用计数大于或等于初始化值,之后便对这些值进行恢复,减去INITIAL_STRONG_VALUE即可。

/frameworks/rs/cpp/util/RefBase.cpp

bool RefBase::weakref_type::attemptIncStrong(constvoid* 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 releasedif ((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 awayif (curCount <=0) {// the last strong-reference got released, the object cannot// be revived.
                decWeak(id);returnfalse;
            }// 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);returnfalse;
            }
        }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 revivedif (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {// it didn't so give-up.
                decWeak(id);returnfalse;
            }// 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;
    }returntrue;
}

  返回到promote函数中,如果attemptIncStrong返回true提升指针成功,set_pointer函数将wp中的m_ptr成员保存在sp中,最后返回这个sp对象,指针提升完成。

/frameworks/rs/server/StrongPointer.h

template<typenameT>
void sp<T>::set_pointer(T* ptr) {
    m_ptr = ptr;
}

总结

  sp化后,强弱引用计数各增加1,sp析构后,强弱引用计数各减1。
  wp化后,弱引用计数增加1,wp析构后,弱引用计数减1。

  • 作者:Invoker123
  • 原文链接:https://blog.csdn.net/Invoker123/article/details/77814566
    更新时间:2023-09-13 08:05:23