众多周知,指针在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