C++没有像Java那样的内建的对象自动回收机制,new创建的对象没有delete,会一直存在于内存中。对象已经不再使用,但是如果忘记 delete,会造成内存资源的泄露。在实际开发过程中,分析内存泄露是一件很棘手的事情。本文基于Android2.2系统源码,对Android的 C++对象自动回收机制进行分析。
Android上C++对象实现自动释放的机制是使用引用计数+智能指针。对象的生命周期通过引用计数来管理,当引用计数>0时,对象不会被释放;当引用计数=0时,释放该对象。
使用对象的方式是通过智能指针引用该对象,智能指针也是C++对象,利用C++的构造析构自动调用的特性,在构造函数中将对象的引用计数加1,析构函数中减1,当计数减为0时delete该对象,这样通过智能指针+引用计数就实现了对象的自动化管理。
下面通过代码分析具体实现过程。
Android中C++类一般都会直接或间接继承RefBase类,RefBase类有一个成员变量mRefs,mRefs是 weakref_impl类型,weakref_impl记录着引用计数、目标对象(通过引用计数管理的对象)指针和符号位。通过继承RefBase,使 类具有引用计数的功能。
1 |
weakref_impl* const mRefs; |
1 |
class RefBase::weakref_impl : public RefBase::weakref_type |
2 |
{ |
3 |
public : |
4 |
volatile int32_t mStrong; // 强引用计数 |
5 |
volatile int32_t mWeak; // 弱引用计数 |
6 |
RefBase* const mBase; // 目标对象 |
7 |
volatile int32_t mFlags; // 标志位,初始是OBJECT_LIFETIME_STRONG |
8 |
… |
9 |
}; |
1 |
RefBase::RefBase() |
2 |
3 |
: mRefs( new weakref_impl( this )) |
4 |
5 |
{}; |
在讨论智能指针前我们先考虑这样一种情况。假设A对象是由MA模块来创建和销毁的,MB模块的B对象增加A对象的引用计数来使用A对象,有一种情况 是:MA模块比MB模块提前被销毁,由于B对象使用着A,A的引用计数不为0,则A不会被销毁。在MA销毁后B继续使用A,假设A使用了MA模块的其他对 象或者资源,这时就会出问题,因为MA模块的其他对象或者资源已经销毁了。
为了解决上述问题,引用计数细分为强引用计数和弱引用计数。一般情况下,强引用计数控制着对象生命周期,如果强引用计数减为0时目标对象自动析构,即使弱引用计数不为0。弱引用计数后面介绍。
前面说过,智能指针管理着对象的引用计数,Android中智能指针的实现是sp和wp。sp是strong pointer,wp是weak pointer。sp增加引用计数会分别将强引用计数和弱引用计数+1,wp增加引用计数时只会讲弱引用计数+1,。因此,弱引用计数总是 >= 强引用计数。sp可以保证目标对象一直是有效的,但wp不能保证,因此wp不能直接调用目标对象的方法,wp需要提升为sp后才能调用目标对象的方法。所 以wp没有提供指针操作符重载方法(operator* ()和operator->)。
sp和wp分别定义在
frameworks/base/include/utils/StrongPointer.h和frameworks/base/include/utils/RefBase.h文件。
sp对象构造调用incStrong
01 |
template < typename T> |
02 |
03 |
sp<T>::sp(T* other) |
04 |
05 |
: m_ptr(other) |
06 |
07 |
{ |
08 |
09 |
if (other) other->incStrong( this ); |
10 |
11 |
} |
01 |
void RefBase::incStrong( const void * id) const |
02 |
{ |
03 |
weakref_impl* const refs = mRefs; |
04 |
refs->incWeak(id); // mWeak += 1 |
05 |
const int32_t c = android_atomic_inc(&refs->mStrong); // mStrong += 1 |
06 |
… |
07 |
if (c != INITIAL_STRONG_VALUE) { |
08 |
return ; |
09 |
} |
10 |
… |
11 |
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); |
12 |
} |
1 |
template < typename T> |
2 |
sp<T>::~sp() |
3 |
{ |
4 |
if (m_ptr) m_ptr->decStrong( this ); |
5 |
} |
01 |
void RefBase::decStrong( const void * id) const |
02 |
{ |
03 |
… |
04 |
const int32_t c = android_atomic_dec(&refs->mStrong); // mStrong += 1 |
05 |
… |
06 |
if (c == 1) { |
07 |
… |
08 |
if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { |
09 |
delete this ; |
10 |
} |
11 |
} |
12 |
refs->decWeak(id); // mWeak -= 1 |
13 |
} |
wp对象的构造和析构过程也是类似的,构造时mWeak加1,析构时mWeak减1
wp对象调用promote方法返回sp对象,如果sp指向的对象已经销毁,promote返回NULL
1 |
template < typename T> |
2 |
sp<T> wp<T>::promote() const |
3 |
{ |
4 |
sp<T> result; |
5 |
if (m_ptr && m_refs->attemptIncStrong(&result)) { |
6 |
result.set_pointer(m_ptr); |
7 |
} |
8 |
return result; |
9 |
} |
可以将wp提升为sp的三种情况:
1、 没有sp指向目标对象且mStrong == INITIAL_STRONG_VALUE
2、 没有sp指向目标对象且mStrong == 0 且mFlags == OBJECT_LIFETIME_WEAK
3、有sp指向目标对象
attemptIncStrong()代码说明了上面的三种情况
01 |
bool RefBase::weakref_type::attemptIncStrong( const void * id) |
02 |
03 |
{ |
04 |
05 |
incWeak(id); |
06 |
07 |
weakref_impl* const impl = static_cast <weakref_impl*>( this ); |
08 |
09 |
int32_t curCount = impl->mStrong; |
10 |
11 |
LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow" , |
12 |
13 |
this ); |
14 |
15 |
while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) { |
16 |
17 |
if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) { |
18 |
19 |
break ; |
20 |
21 |
} |
22 |
23 |
curCount = impl->mStrong; |
24 |
25 |
} |
26 |
27 |
if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) { |
28 |
29 |
bool allow; |
30 |
31 |
if (curCount == INITIAL_STRONG_VALUE) { |
32 |
33 |
// Attempting to acquire first strong reference... this is allowed |
34 |
35 |
// if the object does NOT have a longer lifetime (meaning the |
36 |
37 |
// implementation doesn't need to see this), or if the implementation |
38 |
39 |
// allows it to happen. |
40 |
41 |
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK |
42 |
43 |
|| impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id); |
44 |
45 |
} else { |
46 |
47 |
// Attempting to revive the object... this is allowed |
48 |
49 |
// if the object DOES have a longer lifetime (so we can safely |
50 |
51 |
// call the object with only a weak ref) and the implementation |
52 |
53 |
// allows it to happen. |
54 |
55 |
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK |
56 |
57 |
&& impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id); |
58 |
} |
59 |
if (!allow) { |
60 |
decWeak(id); |
61 |
return false ; |
62 |
} |
63 |
64 |
curCount = android_atomic_inc(&impl->mStrong); |
65 |
… |
66 |
67 |
} |
68 |
} |
69 |
impl->addStrongRef(id); |
70 |
71 |
… |
72 |
73 |
return true ; |
74 |
75 |
} |
当mFlags 为OBJECT_LIFETIME_STRONG 时,强引用计数为0时,销毁对象
当mFlags为OBJECT_LIFETIME_WEAK时,强引用计数为0时,不销毁对象,弱引用减为0时,才销毁对象,由于弱引用计数 >= 强引用计数,所以OBJECT_LIFETIME_WEAK延长了对象的存在时间,下面的代码说明了这种情况。当mWeak == 0 且 mFlags == OBJECT_LIFETIME_WEAK时,释放目标对象。
01 |
void RefBase::weakref_type::decWeak( const void * id) |
02 |
{ |
03 |
const int32_t c = android_atomic_dec(&impl->mWeak); |
04 |
if (c != 1) return ; |
05 |
if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) { |
06 |
… |
07 |
} else { |
08 |
// less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER} |
09 |
impl->mBase->onLastWeakRef(id); |
10 |
if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) { |
11 |
// this is the OBJECT_LIFETIME_WEAK case. The last weak-reference |
12 |
// is gone, we can destroy the object. |
13 |
delete impl->mBase; |
14 |
} |
15 |
} |
16 |
} |
RefBase提供了以下四个重载方法,子类可以继承实现,以便跟踪引用计数的变化情况。
1 |
// 当mStrong从INITIAL_STRONG_VALUE更改为1时,该方法被调用 |
2 |
virtual void onFirstRef(); |
3 |
// 当mStrong从减为0时,该方法被调用 |
4 |
virtual void onLastStrongRef( const void * id); |
5 |
// 控制是否允许将wp提升为sp,返回true表示允许 |
6 |
virtual bool onIncStrongAttempted(uint32_t flags, const void * id) |
7 |
// 当mWeak减为0时且mFlags == OBJECT_LIFETIME_WEAK,该方法被调用 |
8 |
virtual void onLastWeakRef( const void * id); |
RefBase为C++对象提供了引用计数,sp和wp通过管理引用计数,达到自动控制目标对象生存期的目的。