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

提供引用计数器的类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掉了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/336230.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【WebRTC---入门篇】(十五)WebRTC信令服务器实现

如何使用socket.io发送消息 io代表整个节点

气味识别应用_代码气味–第二部分

气味识别应用在上一篇文章《代码气味–第一部分》中 &#xff0c;我谈到了膨胀器&#xff1a;它们是代码气味&#xff0c;可以识别为长方法&#xff0c;大型类&#xff0c;原始痴迷&#xff0c;长参数列表和数据块。 在这一篇中&#xff0c;我想深入研究面向对象的滥用者和变更…

activiti高亮显示图片_如今透明LED显示屏成为广告橱窗,它们之间有什么关联?...

如今我们在街道行走时&#xff0c;我们就会看到各种玻璃橱窗&#xff0c;这是商家想利用橱窗进行不同产品宣传角度。其实无论是海报、灯箱或是实物展示&#xff0c;这些都是商家通过橱窗广告进行来吸引消费者&#xff0c;而现在是5G时代到来使橱窗数字化营销成为了一种新的趋势…

theme editor android,谷歌宣布将于下月停用 Material Theme Editor

使用 Material Theme Editor&#xff0c;开发人员可创建和自定义 Material 主题&#xff0c;包括颜色、形状、版式等等。在 Material Theme Editor 中&#xff0c;可根据不同部分依次选择颜色&#xff0c;并应用于所有组件&#xff0c;还可调整对比度&#xff0c;根据单一颜色自…

【WebRTC---入门篇】(十六)端对端1V1传输基本流程

RTCPeerConnection 媒体协商 setLocalDescription方法 ,收集所有候选者。 setRemoteDescription方法, 放到远端的描述槽中。 协商状态变化

pytorch dataset_【小白学PyTorch】16.TF2读取图片的方法

<>扩展之tensorflow2.0 | 15 TF2实现一个简单的服装分类任务小白学PyTorch | 14 tensorboardX可视化教程小白学PyTorch | 13 EfficientNet详解及PyTorch实现小白学PyTorch | 12 SENet详解及PyTorch实现小白学PyTorch | 11 MobileNet详解及PyTorch实现小白学PyTorch | 10 …

android 硬件对接,Android 对接硬件串口篇

private DispQueueThread DispQueue;private AssistBean AssistData;private SerialControl ComA;Overridepublic void initView() {ComA new SerialControl();//开启串口DispQueue new DispQueueThread();//开启线程实时获取数据DispQueue.start();//线程启动AssistData ge…

【WebRTC---入门篇】(十七)实现1V1音视频实时互动直播系统

STUN/TURN服务器搭建 详细搭建过程 RTCPeerConnection

junit5和junit4_JUnit 5 –架构

junit5和junit4现在我们知道如何设置JUnit 5并使用它编写一些测试 &#xff0c;下面让我们看一下。 在本文中&#xff0c;我们将讨论JUnit 5架构以及采用这种方式的原因。 总览 这篇文章是有关JUnit 5的系列文章的一部分&#xff1a; 建立 基本 建筑 条件 注射 … JUni…

pytorch load state dict_PyTorch 学习笔记(五):Finetune和各层定制学习率

本文截取自《PyTorch 模型训练实用教程》&#xff0c;获取全文pdf请点击&#xff1a;https://github.com/tensor-yu/PyTorch_Tutorial [toc]我们知道一个良好的权值初始化&#xff0c;可以使收敛速度加快&#xff0c;甚至可以获得更好的精度。而在实际应用中&#xff0c;我们通…

华为配备鸿蒙系统的手机,华为P50/新平板双双来袭!全球首发鸿蒙系统:配置都非常强悍...

【12月12日讯】相信大家都知道&#xff0c;华为方面已经正式官宣&#xff0c;将会在12月16日正式推出鸿蒙系统首个手机Bate版本&#xff0c;但也有很多网友们担忧&#xff0c;华为手机在脱离了Android系统以后&#xff0c;鸿蒙OS系统是否真的可以击败Android系统&#xff0c;第…

【WebRTC---入门篇】(十八)WebRTC非音视频数据传输

WebRTC传输非音视频重要API createDataChannel options ordered 在传输非音视频的时候是否是按序到达的。 maxPacketLifeTime/maxRetransmits 最大包存活时间;最大传输次数。两者二选一 negotiated ID 唯一标识 DataChannel事件

ios 静音模式_静音设计模式

ios 静音模式您最近是否遵循Mute-Design-Pattern™编写了大量代码&#xff1f; 例如 try {complex();logic();here(); } catch (Exception ignore) {// Will never happen heheSystem.exit(-1); }Java 8有一个更简单的方法&#xff01; 只需将这个非常有用的工具添加到您的Ut…

datatable使用_使用Streamlit从简单的Python脚本创建交互式WebApp

如果有人告诉您可以使用150-200行代码创建交互式Web应用程序&#xff0c;该怎么办&#xff1f; 有趣的权利。 Streamlit为您提供了使用简单的python脚本和一些streamlit调用来创建漂亮的Web应用程序的相同机会。Streamlit是一个开放源代码框架&#xff0c;用于以最快的方式创建…

和谐 平等_平等还是认同?

和谐 平等将对象存储在集合中时&#xff0c;同一对象永远不能添加两次很重要。 这是集合的核心定义。 在Java中&#xff0c;使用两种方法来确定两个引用的对象是否相同&#xff0c;或者它们都可以存在于同一Set中。 equals&#xff08;&#xff09;和hashCode&#xff08;&…

html监控用户在线与离线,HTML5判断设备在线离线及监听网络状态变化例子

经测试android ipad默认的浏览器支持&#xff0c;用appcan封装的网页也支持html>网络在线与离线$$function(id){return document.getElementById(id);};if(navigator.onLine){$$("status").innerHTML"第一次加载时在线";}else{$$("status").i…

opengl如何画出一个球_OpenGL-Controlling and Monitoring the Pipeline

全球图形学领域教育的领先者、自研引擎的倡导者、底层技术研究领域的技术公开者&#xff0c;东汉书院在致力于使得更多人群具备内核级竞争力的道路上&#xff0c;将带给小伙伴们更多的公开技术教学和视频&#xff0c;感谢一路以来有你的支持。我们正在用实际行动来帮助小伙伴们…

【WebRTC---入门篇】(二十)WebRTC核心之SDP详解

SDK规范 会话层 媒体层 SDP规范相关参考 WebRTC中的SDP

junit5和junit4_JUnit 5 –条件

junit5和junit4最近&#xff0c;我们了解了JUnit的新扩展模型以及它如何使我们能够将自定义行为注入测试引擎。 我向你保证要看情况。 现在就开始吧&#xff01; 条件允许我们在应该执行或不应该执行测试时定义灵活的标准。 它们的正式名称是“ 条件测试执行” 。 总览 本系列…