您的位置:首页 > 移动开发 > Android开发

Android SP 介绍

2016-04-06 11:36 435 查看
Android系统的运行时库层代码是用C++来编写的,用C++来写代码最容易出错的地方就是指针了,一旦使用不当,轻则造成内存泄漏,重则造成系统崩溃。不过系统为我们提供了智能指针,避免出现上述问题,本文将系统地分析Android系统智能指针(轻量级指针、强指针和弱指针)的实现原理。
在使用C++来编写代码的过程中,指针使用不当造成内存泄漏一般就是因为new了一个对象并且使用完之后,忘记了delete这个对象,而造成系统崩溃一般就是因为一个地方delete了这个对象之后,其它地方还在继续使原来指向这个对象的指针。为了避免出现上述问题,一般的做法就是使用引用计数的方法,每当有一个指针指向了一个new出来的对象时,就对这个对象的引用计数增加1,每当有一个指针不再使用这个对象时,就对这个对象的引用计数减少1,每次减1之后,如果发现引用计数值为0时,那么,就要delete这个对象了,这样就避免了忘记delete对象或者这个对象被delete之后其它地方还在使用的问题了。但是,如何实现这个对象的引用计数呢?肯定不是由开发人员来手动地维护了,要开发人员时刻记住什么时候该对这个对象的引用计数加1,什么时候该对这个对象的引用计数减1,一来是不方便开发,二来是不可靠,一不小心哪里多加了一个1或者多减了一个1,就会造成灾难性的后果。这时候,智能指针就粉墨登场了。首先,智能指针是一个对象,不过这个对象代表的是另外一个真实使用的对象,当智能指针指向实际对象的时候,就是智能指针对象创建的时候,当智能指针不再指向实际对象的时候,就是智能指针对象销毁的时候,我们知道,在C++中,对象的创建和销毁时会分别自动地调用对象的构造函数和析构函数,这样,负责对真实对象的引用计数加1和减1的工作就落实到智能指针对象的构造函数和析构函数的身上了,这也是为什么称这个指针对象为智能指针的原因。
解了这些背景知识后,我们就可以进一步学习Android系统的智能指针的实现原理了。Android系统提供了强大的智能指针技术供我们使用,这些智能指针实现方案既包括简单的引用计数技术,也包括了复杂的引用计数技术,即对象既有强引用计数,也有弱引用计数,对应地,这三种智能指针分别就称为轻量级指针(Light Pointer)、强指针(Strong Pointer)和弱指针(Weak Pointer)。无论是轻量级指针,还是强指针和弱指针,它们的实现框架都是一致的,即由对象本身来提供引用计数器,但是它不会去维护这个引用计数器的值,而是由智能指针来维护


轻量级指针 LightRefBase

这个类的实现比较简单, 如果要实现轻量级指针就需要配合使用 sp 合 LightRefBase继承者,通常我们需要使用轻量级指针的目标需要集成 LightRefBase 这个基类,然后放到容器 sp里面就可以实现自动维护垃圾回收,如下是这个类的简要分析:

template

class LightRefBase

{

public:

inline LightRefBase() : mCount(0) { }

inline void incStrong(attribute((unused)) const void* id) const {

android_atomic_inc(&mCount);

}

inline void decStrong(attribute((unused)) const void* id) const {

if (android_atomic_dec(&mCount) == 1) {

delete static_cast

if PRINT_REFS

ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);


endif

if (c != INITIAL_STRONG_VALUE)  {
return;
}
//如果是第一次强引用这个目标, 就会取回调这个对象的onFirstRef,可以客制化对应的操作
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
refs->mBase->onFirstRef();


}

注意在构造函数的时候主要做的事情总结就是增加 weak ref count, 增加 string ref count, 然后判断是否是第一次强引用这个目标,是就回调onFirstRef, 这里不设计到对象的释放,再来看sp的析构函数:

template

sp::~sp()

{

if (m_ptr) m_ptr->decStrong(this);

}

这里就是直接call refbase的 decStrong, 继续分析这个函数:

void RefBase::decStrong(const void* id) const

{

weakref_impl* const refs = mRefs;

const int32_t c = android_atomic_dec(&refs->mStrong);
if (c == 1) {
refs->mBase->onLastStrongRef(id);
if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
delete this;
}
}
refs->decWeak(id);


}

这里主要做的动作就是先减少强引用计数,然后这里就需要进行判断了, 如果强引用计数为0, 就可能需要delete 目标对象, 但是这个还需要进行判断,就是之前的flag, 如果这个flag设置为OBJECT_LIFETIME_STRONG, 意思就是说只要强引用计数为0, 就可以delete, 如果不是, 就可能需要判断弱引用计数,最后减少弱引用计数, refs->decWeak(id);, 再分析这个函数:

void RefBase::weakref_type::decWeak(const void* id)

{

weakref_impl* const impl = static_cast
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  sp-wp strong pointer