分类: Android平台
2014-08-18 17:07:18
转载自:
在Android native编写代码时,会经常接触到sp、wp,sp并不是smart pointer的意思,而是strong point;wp就是weak pointer。这两个概念比较像JAVA中的强弱引用,使用sp和wp可以让人员不需要再关系内存的释放问题,防止内存泄露。下面先来看它们的类关系图:
要实现内存的自动释放,sp、wp必须结合RefBase这个类来使用,在Android中,大多数类的最上层基类都是RefBase类。我们举个简单的例子,然后顺着这个例子来分析RefBase、sp和wp四种不同的应用,并介绍其实现。<喎?"" target="_blank" class="keylink">vcD4KPHA+PC9wPgo8cHJlIGNsYXNzPQ=="brush:java;">class A : public RefBase { }
上面定义一个类A,继承与RefBase,下面我们首先来看RefBases的构造函数:
1
2
3
4
5
6
7
8
9
10
11
12
|
RefBase::RefBase()
: mRefs(newweakref_impl(this))
{
}
weakref_impl(RefBase* base)
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
, mFlags(0)
{
}
|
在RefBase中,首先构造weakref_impl对象,在weakref_impl对mStong和mWeak进行强弱引用计数赋初始值,INITIAL_STRONG_VALUE是0X10000000,这里不直接赋初始值为0,是方便我们区分,0到底是初始化的值,还是在sp释放后再变为0,方便做不同的处理。
列举第一种应用:只有sp指针,没有wp指针的应用
{
sp
1
2
3
4
5
6
|
template
sp
: m_ptr(other) {
if(other)
other->incStrong(this);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
voidRefBase::incStrong(constvoid* id)const
{
weakref_impl*constrefs = mRefs;
refs->incWeak(id);
refs->addStrongRef(id);
constint32_t c = android_atomic_inc(&refs->mStrong);
ALOG_ASSERT(c >0,"incStrong() called on %p after last strong ref", refs);
if(c != INITIAL_STRONG_VALUE) {
return;
}
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
refs->mBase->onFirstRef();
}
|
1
2
3
4
5
6
7
|
voidRefBase::weakref_type::incWeak(constvoid* id)
{
weakref_impl*constimpl = static_cast
impl->addWeakRef(id);
constint32_t c = android_atomic_inc(&impl->mWeak);
ALOG_ASSERT(c >=0,"incWeak called on %p after last weak ref",this);
}
|
这里还是调用android_atomic_inc去增加weakref_impl的mWeak计数。经过构造函数,mStong和mWeak的计数都变成了1。当spA对象退出作用域以后,就会调用其析构函数来释放这个对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
template
sp
if(m_ptr)
m_ptr->decStrong(this);
}
voidRefBase::decStrong(constvoid* id)const
{
weakref_impl*constrefs = mRefs;
refs->removeStrongRef(id);
constint32_t c = android_atomic_dec(&refs->mStrong);
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);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
voidRefBase::weakref_type::decWeak(constvoid* id)
{
weakref_impl*constimpl = static_cast
impl->removeWeakRef(id);
constint32_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) {
if(impl->mStrong == INITIAL_STRONG_VALUE) {
delete impl->mBase;
}else{
delete impl;
}
}else{
impl->mBase->onLastWeakRef(id);
if((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
delete impl->mBase;
}
}
}
|
函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
RefBase::~RefBase()
{
if(mRefs->mStrong == INITIAL_STRONG_VALUE) {
delete mRefs;
}else{
if((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
if(mRefs->mWeak ==0) {
delete mRefs;
}
}
}
const_cast
}
|
列举第二种应用:只有wp指针,没有sp指针的应用
{
wp
1
2
3
4
5
6
7
8
|
template
wp
: m_ptr(other.m_ptr)
{
if(m_ptr) {
m_refs = m_ptr->createWeak(this);
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
RefBase::weakref_type* RefBase::createWeak(constvoid* id)const
{
mRefs->incWeak(id);
returnmRefs;
}
voidRefBase::weakref_type::incWeak(constvoid* id)
{
weakref_impl*constimpl = static_cast
impl->addWeakRef(id);
constint32_t c = android_atomic_inc(&impl->mWeak);
ALOG_ASSERT(c >=0,"incWeak called on %p after last weak ref",this);
}
|
1
2
3
4
5
|
template
wp
{
if(m_ptr) m_refs->decWeak(this);
}
|
列举第三种应用:既有sp指针,又有wp指针的应用
{
1
2
3
4
5
6
7
8
9
10
|
template
sp
{
sp
if(m_ptr && m_refs->attemptIncStrong(&result)) {
result.set_pointer(m_ptr);
}
returnresult;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
bool RefBase::weakref_type::attemptIncStrong(constvoid* id)
{
incWeak(id);
weakref_impl*constimpl = static_cast
int32_t curCount = impl->mStrong;
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) {
if((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
if(curCount <=0) {
decWeak(id);
returnfalse;
}
while(curCount >0) {
if(android_atomic_cmpxchg(curCount, curCount +1,
&impl->mStrong) ==0) {
break;
}
curCount = impl->mStrong;
}
if(curCount <=0) {
decWeak(id);
returnfalse;
}
}else{
if(!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
decWeak(id);
returnfalse;
}
curCount = android_atomic_inc(&impl->mStrong);
}
if(curCount >0&& curCount < INITIAL_STRONG_VALUE) {
impl->mBase->onLastStrongRef(id);
}
}
impl->addStrongRef(id);
curCount = impl->mStrong;
while(curCount >= INITIAL_STRONG_VALUE) {
if(android_atomic_cmpxchg(curCount, curCount-INITIAL_STRONG_VALUE,
&impl->mStrong) ==0) {
break;
}
curCount = impl->mStrong;
}
returntrue;
}
|
1. 当前面存在sp的引用,即curCount > 0 && curCount != INITIAL_STRONG_VALUE,这时直接让mStrong加1。
2.当前面不存在sp的引用,需要结合Flag去判断。又分为以下几种情况:
一. Flag = OBJECT_LIFETIME_STRONG,并且curCount等于0。说明之前的sp对象已经释放,由前面的知识我们知道,在释放sp对象的同时也会释放对象A,所以这里调用decWeak来释放前面增加的一次mWeak值并返回false
二.Flag = OBJECT_LIFETIME_STRONG,并且curCount = INITIAL_STRONG_VALUE,说明前面没有sp引用,这时我们可以增加mStrong值。
三.Flag = OBJECT_LIFETIME_WEAK,并且curCount <= 0 || curCount == INITIAL_STRONG_VALUE,则调用RefBase的onIncStrongAttempted去尝试增加mStrong值
当上面任何一种情况增加了mStrong值以后,mSrong的值可能大于INITIAL_STRONG_VALUE,我们需要去修正mStrong,就是通过减去INITIAL_STRONG_VALUE计算。当attemptIncStrong返回true时,promote方法就会调用sp的set_pointer方法去设置StrongPointer中的实际A对象的指针。接下来就可以通过sp调用相关的方法了。