内存管理(四) - 源码解读所有权修饰符(一)

聊聊iOS autoreleasepool里的数据结构 iOS autoreleasepool分析 阅读详情

优快云

有道云

__strong 修饰符

1. alloc/new/copy/mutableCopy

赋值给附有__strong 修饰符的变量在实际的程序中到底是这么样运行的呢?

{
    id __strong obj = [[NSObject alloc] init];
}

该源码实际上可以转换为调用以下函数

id obj = objc_msgsend(NSObject, @selector(alloc));
objc_msgSend(obj, @selectro(init));
objc_release(obj);

2次调用了objc_msgSend方法, 变量作用域结束时通过 objc_release 释放对象。虽然 ARC 时不能使用 release 方法,但由此可知编译器自动插入了 release 。

2. alloc/new/copy/mutableCopy 之外
{
     id __strong obj = [NSMutableArray array];
}

虽然调用了我们熟知的 NSMutableArray 类的 array 类方法,但得到的结果却与之前稍有不同。

id obj = objc_msgsend(NSMutableArray, @selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);
objc_retainAutoreleasedReturnValue 函数

objc_retainAutoreleasedReturnValue 函数主要用于最优化程序运行。

顾名思义,它是用于自己持有对象的函数,但它持有的对象应该返回注册在 autoreleasePool 中对象的方法,或者是函数的返回值。像这种,非alloc/new/copy/mutableCopy 的方法,比如 NSMutableArray 类的 array 类方法等调用之后,由编译器插入该函数。

这种 objc_retainAutoreleasedReturnValue 函数是成对的,与之相对的函数是 objc_autoreleaseReturnValue。

objc_autoreleaseReturnValue 函数

objc_autoreleaseReturnValue 用于 非alloc/new/copy/mutableCopy 返回对象的实现上。

+ (id) array {
    retrun [[NSMutableArray alloc] init];
}

源码如下, 调用看 objc_autoreleaseReturnValue 函数

+ (id) array {
   id obj = objc_msgsend(NSMutableArray, @selector(alloc));
   objc_msgSend(obj, @selectro(init));
   retrun objc_autoreleaseReturnValue(obj);
}

像该源代码这样,通过使用 objc_autoreleaseReturnValue 函数,返回注册到 autoreleasePool 中的对象。

但是 objc_autoreleaseReturnValue 函数 与 objc_autorelease 函数不同,一般不仅限于注册到 autoreleasePool 中。

objc_autoreleaseReturnValue 函数会检查使用该函数的方法或者函数调用方的执行命令列表,如果!!! 在方法或者函数的调用方在调用了方法或者函数后紧接着调用了 objc_retainAutoreleasedReturnValue函数,那么就不将返回的对象注册到 autoreleasePool 中,而是直接传递到方法或者函数的调用方。

小结

objc_retainAutoreleasedReturnValue 函数与 objc_retain 函数不同,它即便不注册到 autoreleasePool 中而返回对象,也能够正确的获取对象。

通过 objc_retainAutoreleasedReturnValue 和 objc_autoreleaseReturnValue 函数的协作,可以将对象不注册到 autoreleasePool 中而直接传递, 这一过程到达了最优化。

__weak 修饰符

就像前面我们看到的一样, __wea 修饰符提供的功能如同魔法一般。

  • 若附有__weak 修饰符的变量所引用的对象被废弃,则将 nil 赋值给该变量。
  • 使用附有__weak 修饰符的变量,即是使用注册到 autoreleasePool 中的对象。

这些功能就像魔法一样,到底发生了什么,我们一无所知。

{
    id __weak obj1 = obj;
}

假设变量 obj 附有 __strong 修饰符且对象被赋值.

<!--编译器的模拟代码-->
id obj1;
objc_initWeak(&obj1, obj);
objc_destroyWeak(&obj1); 

通过 objc_initWeak 函数初始化附有 __weak 修饰符的变量。

在变量作用域结束时通过 objc_destroyWeak 函数释放该变量。

如下面代码所示:

objc_initWeak 函数将附有 __weak 修饰符的 变量obj1 初始化为 0 后,会将赋值的对象obj作为参数调用 objc_storeWeak 函数。

obj1 = 0;

objc_storeWeak(&obj1, obj);

objc_destroyWeak 函数将0做参数调用 objc_storeWeak 函数

objc_storeWeak((&obj1, obj)

即使前面的源码和下面源代码相同

id obj1;
obj1 = 0;
objc_storeWeak(&obj1, obj);
objc_storeWeak(&obj1, 0); 
<!--赋值初始化传值,销毁传0(看到这里我的理解)-->
objc_storeWeak 函数

objc_storeWeak 函数把第二参数的赋值对象的地址作为键值,将第一个参数附有__weak 修饰符的变量的地址注册到 weak 表中。如果第二参数为0,则把变量的地址从 weak 表中删除。(验证我前面的理解)

weak 表与引用计数表相同,作为散列表被实现。如果使用 weak表,将废弃对象的地址作为键值进行检索,就能高效地获取对应的附有 __weak 修饰符的变量的地址。另外,由于一个对象可同时赋值给多个附有 __weak 修饰符的变量中,所以对于一个键值,可注册多个变量的地址。

释放对象

释放对象时,废弃谁都不持有的对象的同时,程序的动作是怎样的呢?下面我们来跟踪观察。对象将通过 objc_release 函数释放。

(1) objc_release

(2) 因为引用计数为0所以执行 dealloc

(3) _objc_rootDealloc

(4) objc_dispose

(5) objc_destructInstance   //销毁实例

(6) objc_clear_deallocating //清除回收

对象被废弃时最后调用的 objc_clear_deallocating 函数的动作如下:

(1) 从 weak 表中获取废弃对象的地址为键值的纪录。

(2) 将包含在记录中的所有附有 __weak 修饰符变量的地址,赋值为nil。

(3) 从 weak 表中删除该纪录。

(4) 从引用计数表中删除废弃对象的地址为键值的纪录。

根据以上步骤,前面说的如果附有 __weak 修饰符的变量所引用的对象被废弃,则将 nil 值赋给该变量这一功能即被实现。由此可知如果有大量使用附有 __weak 修饰符的变量,则会消耗相应的 CPU 资源。良策是只在需要避免循环引用时使用 __weak 修饰符。

使用 __weak 修饰符的修饰自己生成并持有的对象
{
  id __weak obj = [[NSObject alloc] init];
}

将自己生成并持有的对象赋值给附有 __weak 修饰符的变量,所以自己并不能持有该对象,这时会被释放并被废弃,因此会引起编译器警告。

id obj ;
id tmp = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(tmp, @selector(init));
objc_initWeak(&obj, tmp);
obj_release(tmp);
objc_destroyWeak(&obj);

虽然自己生成并持有的对象通过 objc_initWeak 函数被赋值给附有 __weak 修饰符的变量中,但编译器判断其并没有持有者,故该对象立即通过 objc_release 函数被释放和废弃。

C++编程语言第三版源码深度解析:从教学示例到工程实践 C++作为一门核心的系统级编程语言,其学习路径往往从理解基础语法和编程范式开始。通过深入剖析经典教材的示例源码,学习者可以系统掌握从变量、函数、面向对象到模板与STL的核心概念及其实现原理。这种基于实例的学习方法,不仅有助于巩固语言基础,更能培养解决实际问题的工程思维。在教学示例中,诸如指针与内存管理、类的封装与多态等关键知识点,通常以聚焦、完整的形式呈现,为理解更复杂的资源管理(如RAII)、错误处理机制提供了清晰的切入点。通过将教学代码进行工程化改造,例如引入头文件分离、异常处理和单元测试,开发者能够将 阅读详情

相关推荐

C++实战编程经典项目源码解析

C++作为一门兼具过程化与面向对象特性的高效编程语言,自诞生以来便在系统开发、游戏引擎、高性能计算等领域占据重要地位。其核心优势在于对底层内存的直接控制能力与高层抽象机制的有机结合,既保留了C语言的高效性,又通过类、模板、异常等特性支持现代软件工程需求。// 示例:RAII 机制的典型应用FILE* fp;public:} // 异常安全的资源释放该机制确保对象析构时自动释放资源,极大提升了程序的异常安全性与可维护性。同时,C++11起引入的智能指针(如。

weixin_32005771的博客 381

objc_autoreleaseReturnValue和objc_retainAutoreleasedReturnValue函数对ARC优化

ARC对注册autoreleasepool优化 在ARC下 Person.m + (instancetype)myPerson { Person *temp = [[Person alloc] init]; return temp; } main.m Person *person = [Person myPerson]; NSArray *array = [[NSArray alloc] initWithObjects:person, nil]; NSLog(@"123"); 非a

wtl1804的博客 1388

Zemax物理光学实战:3分钟搞定高斯光束传播模拟(附菲涅尔局部分析技巧)

本文详细介绍了在Zemax中进行高斯光束传播模拟与菲涅尔局部分析的实战技巧。通过3分钟快速设置指南和参数解析,帮助光学工程师准确模拟激光光束特性,避免常见误区。特别分享了菲涅尔局部分析的关键技巧和传播参数优化策略,提升光学系统设计的精度与效率。

lambda的博客 804

Objective-C中的自动引用计数ARC背后做了什么处理及使用注意点

使用ARC后应该注意什么? 1、由于ARC会自动执行retain、release、autorelease等操作,所以在ARC下不能直接调用这些内存管理方法。 retain release autorelease dealloc 因为ARC要分析何处应该自动调用内存管理方法,所以如果手工调用的话,就会干扰其工作。 2、ARC硬性规定内存管理语义需要在方法名中表示出来。若方法名以下列词语开头,则其返回的对象归调用者所有: alloc new copy mutableCopy 调用了这四种方法

run_in_road的博客 357

海康威视摄像头网线连接笔记本电脑,客户端提示:1连接设备失败。设备不在线或网络原因引起的连接超时等。(HCNetSDK.dll[7].)解决方案

1.环境 电脑:联想笔记本电脑(win10系统) 摄像头:海康威视DS-2CD3T20D-i5,4mm 连接方式:直接用网线将摄像头和摄像头连接 2.问题: 客户端出现如下提示: 3. 解决流程: 1.确认网线是否有问题:我的网线指示灯常亮,并且设备能够被搜索到,只是一直显示离线 2.按照网上教程直接配置摄像头的ip地址与电脑同一网段:登录失败。 错误码为 HCNetSDK.dll[7].(连接设备失败。设备不在【海康威视吧】_百度贴吧 失败了,没有反应 3.查看有线网卡的地

weixin_48911487的博客 3万+

NOTE: When using the `ipython kernel` entry point, Ctrl-C will not work.解决方案

本文主要介绍了NOTE: When using the `ipython kernel` entry point, Ctrl-C will not work.解决方案,希望能对使用jupyter notebook的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 11万+

黑幕背后的Autorelease

原文地址: 我是前言 Autorelease机制是iOS开发者管理对象内存的好伙伴,MRC中,调用[obj autorelease]来延迟内存的释放是一件简单自然的事,ARC下,我们甚至可以完全不知道Autorelease就能管理好内存。而在这背后,objc和编译器都帮我们做了哪些事呢,它们是如何协作来正确管理内存的呢?刨根问底,一起来探究下黑幕背后的Autorelease

993

Python 爬虫实战:爬虫与 ECharts 结合 —— 前端可视化展示

本文介绍了爬虫技术与ECharts可视化结合的完整实现流程。首先使用Python爬取京东商品数据(价格、评价数等),通过BeautifulSoup解析和pandas处理转换为JSON格式。然后构建前端页面,利用ECharts实现价格分布柱状图、价格-评价数散点图和店铺占比饼图三种可视化效果。文章详细解析了爬虫数据提取、格式转换和前端图表配置等关键技术点,并提供了完整的代码示例。最后提出了基于API接口、数据库存储等扩展方向,为数据采集到可视化展示提供了完整的解决方案。

2503_91057718的博客 631

某手rsa分析未完成

v16 = objc_msgSend(v15, "objectForKey:", CFSTR("private")); v17 = objc_retainAutoreleasedReturnValue(v16); v19 = (void *)objc_retainAutorelease(v17, v18); v20 = v19; v21 = (cons

inquisiter 829

科研绘图系列:R语言绘制世界地图数据分布(world map)

科研绘图系列:R语言绘制世界地图数据分布(world map)

专注生信领域 527

调用魔搭API出现Please bind your Alibaba Cloud account before use的解决方案

本文主要介绍了调用魔搭API出现Please bind your Alibaba Cloud account before use解决方案,希望能对使用大模型的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 3万+

Objective-C内存管理:从源码进行分析(二)

通过对《Objective-C高级编程》的学习,就来总结一下。解读相信很多学习iOS编程的人都会认识ARC(自动引用计数),实际上呢,”引用计数内存管理”的本质部分在ARC中并没有改变。根据名字我们可以看出,ARC就是自动帮我们处理”引用计数”的相关部分而已。从编译单位上的角度来讲,我们是可以对ARC进行有效或者无效的设置的。例如有一些文件可以使用ARC,有一些文章不可以使用ARC。 编译单元

LastDays_UIT技术分享 897

ResNet改进(20):融合Swin Transformer与ResNet

这种混合架构的设计理念是:在保留CNN强大局部特征提取能力的同时,引入Transformer的全局建模优势。我们实现的模型在ResNet18的基础上嵌入了一个简化版的Swin Transformer Block,旨在探索两种范式结合的可能性。通过在ResNet早期阶段引入Transformer模块,我们既保留了CNN强大的局部特征提取能力,又获得了Transformer的全局建模优势。本文提出的ResNet与Swin Transformer混合架构,探索了CNN与Transformer结合的可能性。

2401_82355416的博客 859

【Java源码阅读系列6】深度解读Java Object源码

在Java的类继承体系中,Object类是所有类的终极父类(包括数组)。无论我们定义的类是否显式声明extends Object,编译器都会自动添加这一继承关系。这种设计使得Object类成为Java对象的"通用契约"——它定义了所有对象都必须具备的核心能力。本文将基于JDK 1.8的Object类源码,深入解析其核心方法的设计逻辑与使用规范。

专注Java和MySQL领域知识分享 1207

PCL点云处理之计算点到空间直线距离的四种方法(二十三)

PCL点云处理之计算点到空间直线距离的四种方法

weixin_44329757的博客 3022

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

iOS Block

#mermaid-svg-bf4zeaT6GaxRXT7K .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-bf4zeaT6GaxRXT7K .label text{fill:#333}#mermaid-svg-bf4zeaT6GaxRXT7K .node rect,#mermaid-svg-bf4zeaT6Ga

xiaoxiaobukuang的专栏 250

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

360校招iOS开发笔试客观题解析:内存管理、Runtime与多线程考点全拆解

iOS开发岗位的校招笔试中,客观题是快速筛选候选人的重要环节,其考察范围往往集中于Objective-C语言特性、内存管理、Runtime消息机制、多线程与RunLoop等核心基础。理解这些底层原理,不仅能提高笔试正确率,更是日常工程实践中规避循环引用、死锁等线上事故的关键。这类知识点在App开发中无处不在:属性修饰符的选择影响对象生命周期,GCD的使用方式决定并发行为,RunLoop则驱动着UI事件与消息处理。对于正在准备秋招或希望系统自查iOS基础的同学,通过典型真题拆解来梳理知识框架,往往比盲目刷题更

weixin_30595035的博客 423

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Linux 2.6 源码学习-内存管理-buddy算法

核心数据结构 linux 2.6 的内存管理支持NUMA(Non Uniform Memory Access Achitecture),即非一致内存访问体系,在该体系中存在多个CPU,并且拥有分离的存储器以及共享存储器。因此在linux的代码中将每一个CPU的可访问内存定义为一个内存节点。总体上linux采取了节点、域、页面三级结构描述物理内存,核心数据结构如下: typedef struc...

Fred's Note 604

JDK源码分析之String(一)

摘要日常使用java中,java.lang.String类几乎是使用最为频繁的一个类,此系列主要介绍String的具体实现以及作者对其进行了什么样的优化操作

记忆流年的博客 753

scala的list源码解密

今日【DT大数据梦工厂视频】《第83讲:Scala中List的实现内幕源码揭秘》51CTO视频:http://edu.51cto.com/lesson/id-71363.html土豆视频:http://www.tudou.com/programs/view/Qp70gLn7jr8/ 优酷视频:http://v.youku.com/v_show/id_XMTMwNjU0NTI0NA==.html...

weixin_30622107的博客 144

String源码解析

字符串类String是Java中常用的一个引用数据类型,有必要对其源码进行了解。 修饰符 public final class String implements java.io.Serializable, Comparable<String>, CharSequence final修饰String,因此String不能被继承,用String创建的字符串也不能被修改。同时,它实现了序列化接口,表明其可以被写入文件或数据库、在网络上进行传输、在进程间传递对象;实现了Comparable接

Show My Cheap Code 214

app启动速度优化,想给金三银四找工作的程序员几点建议,挥泪整理面经

这篇文章主要介绍了20道经典Handler题及答案解析,文中通过示例代码介绍的非常详细,对大家的学习或者面试复习具有一定的参考学习价值,内容过多可以先收藏慢慢观看,需要的朋友们下面随着小编来一起学习学习吧。 另外各位观众老爷觉得内容还可以的,请给个赞和评论,你的点赞和评论是我最大的动力,谢谢! 一、Java初中级面试题 1.容器(HashMap、HashSet、LinkedList,HashSet等) 2.内存模型 3.JVM、Davilk、ART 三者的原理和区别 4.垃圾回收机制 5.类加载方案 6.

m0_56037919的博客 109

顺丰科技iOS秋招客观题解析:内存管理、Runtime与多线程高频考点精讲

在iOS开发岗位的笔试与面试中,对Objective-C底层机制的理解程度往往决定了候选人能否从众多竞争者中脱颖而出。内存管理作为iOS开发的核心基石,涵盖了weak与copy修饰符的底层差异、block的捕获机制以及ARC下的循环引用问题;而Runtime则赋予Objective-C动态性,消息转发流程与KVO的isa-swizzling实现是区分“会用”和“懂原理”的分水岭。多线程场景下,GCD队列与死锁的关系、atomic的局限也是工程实践中常踩的坑。这些知识不仅支撑着App的稳定性与性能表现,更在物

weixin_34262482的博客 289

Java基础——StringBuilder和StringBuffer

此文主要针对StringBuffer和StringBuilder做一些解读。

WanguideShenghuo的博客 2829

CPython 编译器设计解析:从源码到字节码的完整流水线

在 CPython 中,"编译"指的是把 Python 源代码翻译成可被虚拟机执行的字节码(bytecode)这一整套过程。本文以 CPython 官方内部文档 [InternalDocs/compiler.md](https://link.gitcode.com/i/4c2d3de1730d76ed992cddd3d21229a4) 为核心骨架,结合本仓库 [Parser/](https://l

gitblog_00629的博客 335

Java经典面试题(一)-不古出品

Java经典面试题-不古出品一、Java 基础1.JDK 和 JRE 有什么区别?2.== 和 equals 的区别是什么?3.两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?4.final 在 java 中有什么作用?5.java 中的 Math.round(-1.5) 等于多少?6.String 属于基础的数据类型吗?7.java 中操作字符串都有哪些类?它们之间有什么区别?8.String str="i"与 String str=new String(“i”)一样吗

不古的博客 1575
上一篇: 内存管理(二) - MRC关键字解读
下一篇: NSTimer循环引用分析,解决
Code_浅蓝
博客等级 码龄11年 28粉丝 42原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值