首页 > 代码库 > Android 智能指针
Android 智能指针
众多周知,指针在C/C++是一个很重要的手段,但是也是最让人麻烦的东西,容易出现空指针,或者内存泄漏,无非是new了一个对象,没有对应的delete,长时间运行导致系统崩溃!
在android系统中其实也有这个指针这个概念,只不过被用另外的一种安全机制弥补以上的麻烦。
一.概念:
android的中间层frameworks中的JNI以及往下的libraries 运行库层大部分使用的是C++来写的,目的是为了提高效率,在这些地方就需要用到指针了!
android 提供了一套机制为智能指针:
智能指针本身为一个对象,是一个模板类,可以当作一个控制类。有 sp wp 这两个类,后面介绍。
通过对指针指向的对象进行引用计数控制,来决定delete对象,不会遗漏new出来无用的对象,只要还有指针还指向目标对象,那么就不会delete该对象 也杜绝了指针指空的现象!
智能指针用法分三种类型:
1.轻量级指针
2.强指针
3.弱指针
二.轻量级指针:
目标对象的引用计数类为:/frameworks/native/include/utils/RefBase.h 中的 LightRefBase 类,也就是说智能指针指向的对象是继承于LightRefBase这个父类或者间接父类的!
template <class T> class LightRefBase { public: inline LightRefBase() : mCount(0) { } inline void incStrong(const void* id) const { android_atomic_inc(&mCount); } inline void decStrong(const void* id) const { if (android_atomic_dec(&mCount) == 1) { delete static_cast<const T*>(this); } } ... }
可以看到由mCount 一个变量来计数,初始为0,有incStrong decStrong 这个两个方法 来操作 mCount 。
这个计数类比较简单,接口方法只有 sp 类才有,所以我的理解 轻量级的指针只是因为计数类比较简单,智能指针控制类和强指针的类型一样都是 sp!
看看 sp 类:
android4.2 在/frameworks/native/include/utils/StrongPointer.h中定义.
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(); ... }
sp 就是一个智能指针对象,当指向某一个对象的时候,就会创建,当不需要指向某一个对象的时候,也就是这个指针销毁的时候,分别会调用构造函数和析构函数。
看看sp 指针类的构造和析构:
template<typename T> sp<T>::sp(T* other) : m_ptr(other) { if (other) other->incStrong(this); } template<typename T> sp<T>::sp(const sp<T>& other) : m_ptr(other.m_ptr) { if (m_ptr) m_ptr->incStrong(this); }
template<typename T> sp<T>::~sp() { if (m_ptr) m_ptr->decStrong(this); }
可以看到分别调用的是引用的对象的incStrong 和 decStrong 分别对应LightRefBase的计数加1 和 减1 ,可以看到当mCount=1 的时候 再 decStrong 就会 delete对象!
三.强指针:
和轻量级指针不同,强指针用RefBase类计数,同样需要用强指针的也得继承了这个类,也在/frameworks/native/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 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; };
这个类有点复杂,知道几个重要的函数就可以了,这个计数类也提供了 incStrong 和 decStrong这两个控制计数的函数
所谓强指针,肯定是比轻量级的复杂,包含了轻量级的简单计数以外,还区分了计数的类型,分强引用的计数和弱引用的计数,这个两个计数器的值都能起到决定是否delete的作用,
这样做的原因是因为,如果在两个对象之间。互相通过指针引用了对象,当两个对象都不需要用到的时候,就无法单独回收一个对象,定义一个规则 在某个对象的强引用计数为0的时候 不管弱引用多少 都delete 就能解决这一问题
在嵌套引用中就需要设置delete 到底依赖规则,依赖强计数 还是 弱计数 !
这两种计数的变量在RefBase类里面由weakref_impl 类提供 ,也就是 mRefs,看看weakref_impl类:
/frameworks/base/libs/utils/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; #if !DEBUG_REFS weakref_impl(RefBase* base) : mStrong(INITIAL_STRONG_VALUE) , mWeak(0) , mBase(base) , mFlags(0) { } ... }
可以看到前面两个就是两个计数变量,mBase代表这个类对应的RefBase类,
而mFlags就是上面说的依赖规则了,怎么来判定处理前面的两个计数变量!构造函数可以看到 默认为0。对应一个枚举,在RefBase类中的weakref_type类:
enum { OBJECT_LIFETIME_STRONG = 0x0000, OBJECT_LIFETIME_WEAK = 0x0001, OBJECT_LIFETIME_MASK = 0x0001 };
同轻量级一样,在智能指针指向对象的时候,调用指针的构造,这里强指针就是通过 sp 实际调用到对象的incStrong,
也就是 RefBase::incStrong:
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); ... }
android4.2 在incWeak 里面增加了弱引用计数,然后addStrongRef再增加了强计数。强弱计数都+1.
实际处理函数为android_atomic_inc(&refs->mStrong)
同样在销毁的时候调用RefBase::decStrong:
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); }实际处理函数为android_atomic_dec(&refs->mStrong)
可以看到在操作完强计数的时候,会做判断,如果是到0了,然后依赖的处理规则又是强引用,那么就delete这个对象!
不然就往下处理弱引用计数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 = 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; } } }
一样的,做了判断,如果发现到0了然后规则是弱引用处理,就delete
四.弱指针:
弱指针所用的计数类和强指针的一样为RefBase这个类。控制的智能指针不一样而已 为 wp 类,定义在/frameworks/native/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(); ... // promotion to sp sp<T> promote() const; ... }
调用同上面的一样,直接看构造和析构函数:
template<typename T> wp<T>::wp(T* other) : m_ptr(other) { if (other) m_refs = other->createWeak(this); } template<typename T> wp<T>::~wp() { if (m_ptr) m_refs->decWeak(this); }
分别调用到RefBase类里面的实现函数:
构造的:
RefBase::weakref_type* RefBase::createWeak(const void* id) const { mRefs->incWeak(id); return mRefs; }
这里的mRefs 是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); ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this); }
这里只是 弱引用计数 +1
析构的:
直接调用到:
RefBase::weakref_type::decWeak
同上!
另外弱指针有一个特性,就是无法直接操作目标对象,弱指针类没有重载*和->操作符号!
弱指针可以通过promote()方法提升为强指针!
实现函数:RefBase::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; ALOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow", this); 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) { // Attempting to acquire first strong reference... this is allowed // if the object does NOT have a longer lifetime (meaning the // implementation doesn't need to see this), or if the implementation // allows it to happen. allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id); } else { // Attempting to revive the object... this is allowed // if the object DOES have a longer lifetime (so we can safely // call the object with only a weak ref) and the implementation // allows it to happen. 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 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 if (curCount == INITIAL_STRONG_VALUE) { android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong); impl->mBase->onFirstRef(); } return true; }
但是提升为强指针是要看目前弱指针对象是否已经delete,还要看对象有没有设置一些属性导致不被允许提升为强指针
一种情况是 对象整在被其它强指针引用 强引用肯定大于0 可以提升为强指针 然后增加对象强引用计数
第二种情况:
如果没有被其它的强指针引用而且强引用计数等于INITIAL_STRONG_VALUE就要满足:
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
否则就要满足:
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
如果allow为false 就代表不能提升为强指针,那么就要减小目标对象的弱引用计数,因为attempIncStrong 开头就直接增加了弱引用计数!
如果满足条件,往下就增加强引用计数.
五.强弱指针使用范例:
借用一个写的比较形象的范例:
#include <stdio.h> #include <utils/RefBase.h> #define INITIAL_STRONG_VALUE (1<<28) using namespace android; class WeightClass : public RefBase { public: void printRefCount() { int32_t strong = getStrongCount(); weakref_type* ref = getWeakRefs(); printf("-----------------------\n"); printf("Strong Ref Count: %d.\n", (strong == INITIAL_STRONG_VALUE ? 0 : strong)); printf("Weak Ref Count: %d.\n", ref->getWeakCount()); printf("-----------------------\n"); } }; class StrongClass : public WeightClass { public: StrongClass() { printf("Construct StrongClass Object.\n"); } virtual ~StrongClass() { printf("Destory StrongClass Object.\n"); } }; class WeakClass : public WeightClass { public: WeakClass() { extendObjectLifetime(OBJECT_LIFETIME_WEAK); printf("Construct WeakClass Object.\n"); } virtual ~WeakClass() { printf("Destory WeakClass Object.\n"); } }; void TestStrongClass(StrongClass* pStrongClass) { wp<StrongClass> wpOut = pStrongClass; pStrongClass->printRefCount(); { sp<StrongClass> spInner = pStrongClass; pStrongClass->printRefCount(); } sp<StrongClass> spOut = wpOut.promote(); printf("spOut: %p.\n", spOut.get()); } void TestWeakClass(WeakClass* pWeakClass) { wp<WeakClass> wpOut = pWeakClass; pWeakClass->printRefCount(); { sp<WeakClass> spInner = pWeakClass; pWeakClass->printRefCount(); } pWeakClass->printRefCount(); sp<WeakClass> spOut = wpOut.promote(); printf("spOut: %p.\n", spOut.get()); } int main(int argc, char** argv) { printf("Test Strong Class: \n"); StrongClass* pStrongClass = new StrongClass(); TestStrongClass(pStrongClass); printf("\nTest Weak Class: \n"); WeakClass* pWeakClass = new WeakClass(); TestWeakClass(pWeakClass); return 0; }
跑起来的结果:
Test Strong Class: Construct StrongClass Object. ----------------------- Strong Ref Count: 0. Weak Ref Count: 1. ----------------------- ----------------------- Strong Ref Count: 1. Weak Ref Count: 2. ----------------------- Destory StrongClass Object. spOut: 0x0.
可以看到首先是用的一个弱指针去指向对象,所以对象的强引用计数为0 弱引用计数为1
然后中途用一个强指针指向对象,对象的两个引用计数全部加1
退出大括号,销毁强指针,因为默认的强指针是依赖强引用的,上面有说 mFlag 设的是0 ,所在这个时候发现对象的强引用从1变为0了,就delete对象
最后再来用之前的弱指针提升到强指针,因为对象不存在了,所以失败 返回 0x0.
Test Weak Class: Construct WeakClass Object. ----------------------- Strong Ref Count: 0. Weak Ref Count: 1. ----------------------- ----------------------- Strong Ref Count: 1. Weak Ref Count: 2. ----------------------- ----------------------- Strong Ref Count: 0. Weak Ref Count: 1. ----------------------- spOut: 0xa528. Destory WeakClass Object.
这个弱指针的测试前面和上面一样,不同的就是在对象创建的时候 设置了引用计数的依赖规则为 依赖弱引用计数!
所以在中途退出大括号时,不会delete
这个时候提升强指针也满足上面说到过的条件,所以返回0xa528
在程序退出时,弱指针也销毁,这个时候,弱引用计数为0 ,delete 对象!
到这里学习分析完毕!
撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/30070775