提供引用计数器的类RefBase我们就暂时介绍到这里,后面我们再结合智能指针类一起分析,现在先来看看强指针类和弱指针类的定义。强指针类的定义我们在前面介绍轻量级指针的时候已经见到了,就是sp类了,这里就不再把它的代码列出来了。我们来看看它的构造函数的实现:

template

sp::sp(T* other)

: m_ptr(other)

{

if (other) other->incStrong(this);

}

这里传进来的参数other一定是继承于RefBase类的,因此,在函数的内部,它调用的是RefBase类的incStrong函数,它定义在frameworks/base/libs/utils/RefBase.cpp文件中:

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

{

weakref_impl* const refs = mRefs;

refs->addWeakRef(id);

refs->incWeak(id);

refs->addStrongRef(id);

const int32_t c = android_atomic_inc(&refs->mStrong);

LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);

#if PRINT_REFS

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

#endif

if (c != INITIAL_STRONG_VALUE) {

return;

}

android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);

const_cast(this)->onFirstRef();

}

成员变量mRefs是在RefBase类的构造函数中创建的:

RefBase::RefBase()

: mRefs(new weakref_impl(this))

{

//    LOGV("Creating refs %p with RefBase %p\n", mRefs, this);

}

在这个incStrong函数中,主要做了三件事情:

一是增加弱引用计数:

refs->addWeakRef(id);

refs->incWeak(id);

二是增加强引用计数:

refs->addStrongRef(id);

const int32_t c = android_atomic_inc(&refs->mStrong);

三是如果发现是首次调用这个对象的incStrong函数,就会调用一个这个对象的onFirstRef函数,让对象有机会在对象被首次引用时做一些处理逻辑:

if (c != INITIAL_STRONG_VALUE)  {

return;

}

android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);

const_cast(this)->onFirstRef();

这里的c返回的是refs->mStrong加1前的值,如果发现等于INITIAL_STRONG_VALUE,就说明这个对象的强引用计数是第一次被增加,因此,refs->mStrong就是初始化为INITIAL_STRONG_VALUE的,它的值为:#define INITIAL_STRONG_VALUE (1<<28)这个值加1后等于1<<28 + 1,不等于1,因此,后面要再减去-INITIAL_STRONG_VALUE,于是,refs->mStrong就等于1了,就表示当前对象的强引用计数值为1了,这与这个对象是第一次被增加强引用计数值的逻辑是一致的。

回过头来看弱引用计数是如何增加的,首先是调用weakref_impl类的addWeakRef函数,我们知道,在Release版本中,这个函数也不做,而在Debug版本中,这个函数增加了一个ref_entry对象到了weakref_impl对象的mWeakRefs列表中,表示此weakref_impl对象的弱引用计数被增加了一次。接着又调用了weakref_impl类的incWeak函数,真正增加弱引用计数值就是在这个函数实现的了,weakref_impl类的incWeak函数继承于其父类weakref_type的incWeak函数:

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

{

weakref_impl* const impl = static_cast(this);

impl->addWeakRef(id);

const int32_t c = android_atomic_inc(&impl->mWeak);

LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);

}

增加弱引用计数是下面语句执行的:constint32_t c = android_atomic_inc(&impl->mWeak);但是前面为什么又调用了一次addWeakRef函数呢?前面不是已经调用过了吗?在Release版本中,因为weakref_impl类的addWeakRef函数是空实现,这里再调用一次没有什么害处,但是如果在Debug版本,岂不是冗余了吗?搞不清,有人问过负责开发Android系统Binder通信机制模块的作者Dianne Hackborn这个问题,他是这样回答的:

Ah I see.  Well the debug code may be broken, though I wouldn't leap to that

conclusion without actually testing it; I know it has been used in the

past.  Anyway, these things get compiled out in non-debug builds, so there

is no reason to change them unless you are actually trying to use this debug

code and it isn't working and need to do this to fix it.

既然他也不知道怎么回事,我们也不必深究了,知道有这么回事就行。

这里总结一下强指针类sp在其构造函数里面所做的事情就是分别为目标对象的强引用计数和弱引和计数增加了1。

再来看看强指针类的析构函数的实现:

template

sp::~sp()

{

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

}

同样,这里的m_ptr指向的目标对象一定是继承了RefBase类的,因此,这里调用的是RefBase类的decStrong函数,这也是定义在frameworks/base/libs/utils/RefBase.cpp文件中:

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

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

#endif

LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);

if (c == 1) {

const_cast(this)->onLastStrongRef(id);

if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {

deletethis;

}

}

refs->removeWeakRef(id);

refs->decWeak(id);

}

这里的refs->removeStrongRef函数调用语句是对应前面在RefBase::incStrong函数里的refs->addStrongRef函数调用语句的,在Release版本中,这也是一个空实现函数,真正实现强引用计数减1的操作是下面语句:

const int32_t c = android_atomic_dec(&refs->mStrong);

如果发现减1前,此对象的强引用计数为1,就说明从此以后,就再没有地方引用这个目标对象了,这时候,就要看看是否要delete这个目标对象了:

if (c == 1) {

const_cast(this)->onLastStrongRef(id);

if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {

deletethis;

}

}

在强引用计数为0的情况下,如果对象的标志位OBJECT_LIFETIME_WEAK被设置了,就说明这个对象的生命周期是受弱引用计数所控制的,因此,这时候就不能delete对象,要等到弱引用计数也为0的情况下,才能delete这个对象。

接下来的ref->removeWeakRef函数调用语句是对应前面在RefBase::incStrong函数里的refs->addWeakRef函数调用语句的,在Release版本中,这也是一个空实现函数,真正实现强引用计数减1的操作下面的refs->decWeak函数,weakref_impl类没有实现自己的decWeak函数,它继承了weakref_type类的decWeak函数:

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

{

weakref_impl* const impl = static_cast(this);

impl->removeWeakRef(id);

const int32_t c = android_atomic_dec(&impl->mWeak);

LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);

if (c != 1) return;

if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {

if (impl->mStrong == INITIAL_STRONG_VALUE)

deleteimpl->mBase;

else{

//            LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);

deleteimpl;

}

} else{

impl->mBase->onLastWeakRef(id);

if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {

deleteimpl->mBase;

}

}

}

这里又一次调用了weakref_impl对象的removeWeakRef函数,这也是和RefBase::weakref_type::incWeak函数里面的impl->addWeakRef语句所对应的,实现弱引用计数减1的操作是下面语句:constint32_t c = android_atomic_dec(&impl->mWeak);

减1前如果发现不等于1,那么就什么也不用做就返回了,如果发现等于1,就说明当前对象的弱引用计数值为0了,这时候,就要看看是否要delete这个对象了:

if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {

if (impl->mStrong == INITIAL_STRONG_VALUE)

deleteimpl->mBase;

else{

//      LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);

deleteimpl;

}

} else{

impl->mBase->onLastWeakRef(id);

if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {

deleteimpl->mBase;

}

}

如果目标对象的生命周期是不受弱引用计数控制的,就执行下面语句:

if (impl->mStrong == INITIAL_STRONG_VALUE)

deleteimpl->mBase;

else{

//  LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);

deleteimpl;

}

这个代码段是什么意思呢?这里是减少对象的弱引用计数的地方,如果调用到这里,那么就说明前面一定有增加过此对象的弱引用计数,而增加对象的弱引用计数有两种场景的,一种场景是增加对象的强引用计数的时候,会同时增加对象的弱引用计数,另一种场景是当我们使用一个弱指针来指向对象时,在弱指针对象的构造函数里面,也会增加对象的弱引用计数,不过这时候,就只是增加对象的弱引用计数了,并没有同时增加对象的强引用计数。因此,这里在减少对象的弱引用计数时,就要分两种情况来考虑。

如果是前一种场景,这里的impl->mStrong就必然等于0,而不会等于INITIAL_STRONG_VALUE值,因此,这里就不需要delete目标对象了(impl->mBase),因为前面的RefBase::decStrong函数会负责delete这个对象。这里唯一需要做的就是把weakref_impl对象delete掉,但是,为什么要在这里delete这个weakref_impl对象呢?这里的weakref_impl对象是在RefBase的构造函数里面new出来的,理论上说应该在在RefBase的析构函数里delete掉这个weakref_impl对象的。在RefBase的析构函数里面,的确是会做这件事情:

RefBase::~RefBase()

{

//    LOGV("Destroying RefBase %p (refs %p)\n", this, mRefs);

if (mRefs->mWeak == 0) {

//        LOGV("Freeing refs %p of old RefBase %p\n", mRefs, this);

deletemRefs;

}

}

但是不要忘记,在这个场景下,目标对象是前面的RefBase::decStrong函数delete掉的,这时候目标对象就会被析构,但是它的弱引用计数值尚未执行减1操作,因此,这里的mRefs->mWeak == 0条件就不成立,于是就不会delete这个weakref_impl对象,因此,就延迟到执行这里decWeak函数时再执行。

如果是后一种情景,这里的impl->mStrong值就等于INITIAL_STRONG_VALUE了,这时候由于没有地方会负责delete目标对象,因此,就需要把目标对象(imp->mBase)delete掉了,否则就会造成内存泄漏。在delete这个目标对象的时候,就会执行RefBase类的析构函数,这时候目标对象的弱引用计数等于0,于是,就会把weakref_impl对象也一起delete掉了。

android 指针是什么意思,Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析(3)...相关推荐

  1. Android系统在新进程中启动自定义服务过程(startService)的原理分析 (下)

    Step 10. ActivityManagerService.attachApplicationLocked 这个函数定义在frameworks/base/services/java/com/and ...

  2. android多个摄像头,一种基于Android多应用共享摄像头的系统及方法与流程

    本发明涉及一种基于Android多应用共享摄像头的系统及方法,属于计算机领域. 背景技术: 在一些特殊的应用场景.例如后台一直在录像,这时摄像头会被录像应用一直占有,其他的应用无法再打开摄像头.如果其 ...

  3. C++智能指针3——弱指针weak_ptr详解

    目录 shared_ptr指针存在的问题 循环引用示例 代码 运行结果 使用weak_ptr解决循环引用问题 代码 运行结果 共享指针shared_ptr指针存在的问题 使用共享指针shared_pt ...

  4. Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析(3)...

    提供引用计数器的类RefBase我们就暂时介绍到这里,后面我们再结合智能指针类一起分析,现在先来看看强指针类和弱指针类的定义.强指针类的定义我们在前面介绍轻量级指针的时候已经见到了,就是sp类了,这里 ...

  5. Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析【转】...

    Android系统的运行时库层代码是用C++来编写的,用C++ 来写代码最容易出错的地方就是指针了,一旦使用不当,轻则造成内存泄漏,重则造成系统崩溃.不过系统为我们提供了智能指针,避免出现上述问题,本 ...

  6. Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析【转】

    Android系统的运行时库层代码是用C++来编写的,用C++ 来写代码最容易出错的地方就是指针了,一旦使用不当,轻则造成内存泄漏,重则造成系统崩溃.不过系统为我们提供了智能指针,避免出现上述问题,本 ...

  7. ZT自老罗的博客 Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析...

    Android系统的智能指针(轻量级指针.强指针和弱指针)的实现原理分析 分类: Android 2011-09-23 00:59 31568人阅读 评论(42) 收藏 举报 androidclass ...

  8. Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析

    Android系统的运行时库层代码是用C++来编写的,用C++来写代码最容易出错的地方就是指针了,一旦使用不当,轻则造成内存泄漏,重则造成系统崩溃.不过系统为我们提供了智能指针,避免出现上述问题,本文 ...

  9. Android强指针sp和弱指针wp区别

    1.强指针与弱指针概述Android中定义了两种智能指针类型,一种是强指针sp(strong pointer),一种是弱指针(weak pointer). 其实成为强引用和弱引用更合适一些.强指针与一 ...

最新文章

  1. 小问题(可能持续更新)
  2. jsTree 插件Ajax数据
  3. 定义工厂(Plant)
  4. 人脸识别算法不可置疑?真相需要多重验证!
  5. Linux 内核系统架构
  6. 基于RDMA和NVM的大数据系统一致性协议研究
  7. dev c++ 代码补全_学习干货——玩转DEV—C++
  8. js 异步执行_js执行机制:同步与异步(宏任务与微任务)
  9. es的分片和副本_原创|ES广告倒排索引架构演进与优化
  10. 机房环境监控管理解决方案—温湿度、烟感、PM2.5、TVOC等监测
  11. oracle导出导入同义词,oracle同义词语句备份
  12. lbj学习日记 01 选择结构(c++,if,switch)
  13. 阵列信号处理仿真二——波束方向图的绘制
  14. 请帮我查看一下2.19号邢台发往北京高铁的班次,以及各个班次的时间
  15. knockoutjs的学习
  16. 饭局上领导递给你两根烟怎么做(懂得礼数领导赏识重用)
  17. VSCode 安装NPM
  18. webpack打包后的文件夹是空的_深入理解 Webpack 打包分块(下)
  19. 微信小程序:关于物流样式的显示
  20. 东北大学计算机考研哪个方向好,2012考研:东北大学计算机三个方向区别

热门文章

  1. Java 12常规可用性
  2. java实现数据库内容修改_数据库更改到Java环境中实现可持续和平
  3. JDK 12附带紧凑数字格式
  4. Java 8:对速度3.0.1“森林”流ORM的更深入了解
  5. Java EE 7中的WebSocket客户端API
  6. 带有Java 8,lambda表达式和Mockito-Java8附加组件的更紧凑的Mockito
  7. 如何使用单例EJB,Ehcache和MBean构建和清除参考数据缓存
  8. 使用Apache Camel 2.14的轻松REST端点
  9. Java中的SynchronousQueue示例–生产者使用者解决方案
  10. 使用Mockito测试Spring组件