1. 背景
C++没有像Java那样的内建的对象自动回收机制,new创建的对象没有delete,会一直存在于内存中。对象已经不再使用,但是如果忘记 delete,会造成内存资源的泄露。在实际开发过程中,分析内存泄露是一件很棘手的事情。本文基于Android2.2系统源码,对Android的 C++对象自动回收机制进行分析。
2. 引用计数和智能指针
Android上C++对象实现自动释放的机制是使用引用计数+智能指针。对象的生命周期通过引用计数来管理,当引用计数>0时,对象不会被释放;当引用计数=0时,释放该对象。
使用对象的方式是通过智能指针引用该对象,智能指针也是C++对象,利用C++的构造析构自动调用的特性,在构造函数中将对象的引用计数加1,析构函数中减1,当计数减为0时delete该对象,这样通过智能指针+引用计数就实现了对象的自动化管理。
下面通过代码分析具体实现过程。
3. RefBase
Android中C++类一般都会直接或间接继承RefBase类,RefBase类有一个成员变量mRefs,mRefs是 weakref_impl类型,weakref_impl记录着引用计数、目标对象(通过引用计数管理的对象)指针和符号位。通过继承RefBase,使 类具有引用计数的功能。
1 |
weakref_impl* const
mRefs;
|
weakref_impl的定义:
1 |
class
RefBase::weakref_impl : public
RefBase::weakref_type
|
4 |
volatile
int32_t mStrong;
|
5 |
volatile
int32_t mWeak;
|
7 |
volatile
int32_t mFlags;
|
在RefBase的构造函数中,mRefs指向了创建的weakref_impl对象。因此,继承了RefBase的对象都会包含一个weakref_impl对象。
3 |
: mRefs( new
weakref_impl( this ))
|
4. 强引用计数和弱引用计数
在讨论智能指针前我们先考虑这样一种情况。假设A对象是由MA模块来创建和销毁的,MB模块的B对象增加A对象的引用计数来使用A对象,有一种情况 是:MA模块比MB模块提前被销毁,由于B对象使用着A,A的引用计数不为0,则A不会被销毁。在MA销毁后B继续使用A,假设A使用了MA模块的其他对 象或者资源,这时就会出问题,因为MA模块的其他对象或者资源已经销毁了。
为了解决上述问题,引用计数细分为强引用计数和弱引用计数。一般情况下,强引用计数控制着对象生命周期,如果强引用计数减为0时目标对象自动析构,即使弱引用计数不为0。弱引用计数后面介绍。
5. sp和wp
前面说过,智能指针管理着对象的引用计数,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
09 |
if
(other) other->incStrong( this );
|
incStrong将mStrong和mWeak分别加1,mStrong的值从INITIAL_STRONG_VALUE改为1
01 |
void
RefBase::incStrong( const
void * id) const
|
03 |
weakref_impl*
const refs = mRefs;
|
05 |
const
int32_t c = android_atomic_inc(&refs->mStrong);
|
07 |
if
(c != INITIAL_STRONG_VALUE) {
|
11 |
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
|
sp对象析构调用decStrong
4 |
if
(m_ptr) m_ptr->decStrong( this );
|
decStrong分别将mStrong和mWeak 减1,mStrong减为0时。如果mFlags的OBJECT_LIFETIME_STRONG被设置,调用delete this;析构目标对象。OBJECT_LIFETIME_STRONG是默认的情况,后面讨论。
01 |
void
RefBase::decStrong( const
void * id) const
|
04 |
const
int32_t c = android_atomic_dec(&refs->mStrong);
|
08 |
if
((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
|
wp对象的构造和析构过程也是类似的,构造时mWeak加1,析构时mWeak减1
6. wp提升为sp的过程
wp对象调用promote方法返回sp对象,如果sp指向的对象已经销毁,promote返回NULL
2 |
sp<T> wp<T>::promote() const
|
5 |
if
(m_ptr && m_refs->attemptIncStrong(&result)) {
|
6 |
result.set_pointer(m_ptr);
|
可以将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)
|
07 |
weakref_impl*
const impl =
static_cast <weakref_impl*>( this );
|
09 |
int32_t curCount = impl->mStrong;
|
11 |
LOG_ASSERT(curCount >= 0,
"attemptIncStrong called on %p after underflow" ,
|
15 |
while
(curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
|
17 |
if
(android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
|
23 |
curCount = impl->mStrong;
|
27 |
if
(curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
|
31 |
if
(curCount == INITIAL_STRONG_VALUE) {
|
41 |
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
|
43 |
|| impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
|
55 |
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
|
57 |
&& impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
|
64 |
curCount = android_atomic_inc(&impl->mStrong);
|
69 |
impl->addStrongRef(id);
|
7. weakref_impl对象标志位的作用
当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)
|
03 |
const
int32_t c = android_atomic_dec(&impl->mWeak);
|
05 |
if
((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
|
09 |
impl->mBase->onLastWeakRef(id);
|
10 |
if
((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
|
8. 其他特性
RefBase提供了以下四个重载方法,子类可以继承实现,以便跟踪引用计数的变化情况。
2 |
virtual
void onFirstRef();
|
4 |
virtual
void onLastStrongRef( const
void * id);
|
6 |
virtual
bool onIncStrongAttempted(uint32_t flags,
const
void * id)
|
8 |
virtual
void onLastWeakRef( const
void * id);
|
9. 总结
RefBase为C++对象提供了引用计数,sp和wp通过管理引用计数,达到自动控制目标对象生存期的目的。
分享到:
相关推荐
G:\01__docments\02_ebook\c++ 垃圾回收机制
C++内存回收机制,说明继承等C++数据结构如何回收
android与c++通过socket通信 vc6.0开发环境 android与c++通过socket通信 vc6.0开发环境 android与c++通过socket通信 vc6.0开发环境
本书专注于C++面向对象程序设计的底层机制,包括结构式语意、临时性对象的生成、封装、继承,以及虚拟——虚拟函数和虚拟继承。这本书让你知道:一旦你能够了解底层实现模型,你的程序代码将获得多么大的效率。...
The art of c++中的垃圾回收机制实现,对书中代码的bug进行了修改
C++面向对象特性实现机制的初步分析 <br/>1准备知识 1.1 程序对内存的使用方法 1.2 C++ Class内存格局 1.3 编译期和执行期 <br/>2封装 2.1 封装的目的和意义 2.2 封装的实现机制 ...
深度探索C++对象模型 C++程序员必看编程书籍
用C++实现的自动垃圾回收器,是单线程版的
深度探索c++对象模型(2012版本)
《深度探索C++对象模型》专注于C++面向对象程序设计的底层机制,包括结构式语意、临时性对象的生成、封装、继承,以及虚拟——虚拟函数和虚拟继承。这本书让你知道:一旦你能够了解底层实现模型,你的程序代码将获得...
《Android C++高级编程——使用NDK》提供了... 《Android C++高级编程——使用NDK》提供了移植、开发以及利用Android平台上的C++和其他原生代码所需要的知识和技能,以便于运行图形化的高级应用和更复杂的原生应用。
《深度探索C++对象模型》重点探索"对象导向程序所支持的C++对象模型"下的程序行为。...专注于C++对象导向程序设计的底层机制,包括结构式语意、暂时性对象的生成、封装、继承,以及虚拟——虚拟函数和虚拟继承。
深度探索C++对象模型
Android JNI中C++层与Java层的对象交互实例代码详细介绍。Android JNI中C++层与Java层的对象交互实例代码详细介绍。Android JNI中C++层与Java层的对象交互实例代码详细介绍。Android JNI中C++层与Java层的对象交互...
Android利用C++实现RSA、DES、AES、BASE64、MD5,亲测可用,Android利用C++实现RSA、DES、AES、BASE64、MD5,亲测可用
不管你是想将已经存在的原生代码应用移植到Android平台上还是准备开始在Android平台上进行软件开发,使用《Android C++高级编程——使用NDK》一书提供的技术可以构建更出色的应用。本书将展示构建性能更好的复杂原生...
模拟实现android的binder机制在java层、c++层的模型最小例子。实现在不同进程中的通信。
Android 调用C++代码和C++代码调用源码.rar
C++调用Android函数工程Demo详情见博客
深度探索C++对象模型,内容概要:多态是一种威力强大的设计机制,允许你继承一个抽象的public接口之后,封装相关的类型,需要付出的代价就是额外的间接性--不论是在内存的获得,或是在类的决断上,C++通过class的pointer...