当前位置: 首页 > news >正文

iOS ------ ARC的工作原理

一,ARC的概念

ARC (Automatic Reference Counting,自动引用计数) 是苹果公司在其编程语言(如 Objective-C 和 Swift)中的内存管理机制。ARC 通过编译器插入的代码自动管理对象的内存生命周期,减少了手动内存管理的复杂性和错误。

以下是 ARC 在编译期和运行期所做的工作:

二,编译期

1.插入引用计数操作

  • 编译器会在适当的位置插入retain和release操作,retain用于增加对象的引用计数,release用于减少对象的引用计数。
  • 编译器通过静态分析代码,确定在何处增加或减少对象的引用计数
// 示例代码
MyClass *obj = [[MyClass alloc] init]; // 引用计数为1
obj = nil; // 引用计数为0,触发dealloc释放内存

上面的代码,ARC会在编译时插入一下操作

MyClass *obj = [[MyClass alloc] init];
[obj retain]; // 增加引用计数
[obj release]; // 减少引用计数,当obj被赋值为null时

2,优化引用计数操作

编译器会尝试优化引用计数的操作,合并或消除不必要的retain和release调用,例如,编译器会合并多个相邻的retain和release操作减少性能开销

MyClass *obj1 = [[MyClass alloc] init];
MyClass *obj2 = obj1;

在这种情况下,编译器知道ob2是obj1的别名,不需要增加引用计数

3,插入autorelease池管理

  • 对于某些方法(如工厂方法)返回的对象,编译器会插入autorelease调用,使对象在适当的时机释放。
+ (instancetype)myObject {return [[[self alloc] init] autorelease];
}

这里达到了延迟释放对象的效果,autorelease把对象添加到当前的auto release池中,使得对象在某个时刻(通常是当前事件循环结束时)自动释放,而不是立即释放。这种机制允许开发者创建的对象在返回调用者后依旧有效,不会立即释放。

4,生成dealloc方法

  • 编译器会生成或补充类中的dealloc方法来释放实例变量或资源
- (void)dealloc {[_name release];[super dealloc];
}

5,内存管理规则检查

  • 在编译期,ARC 会对代码进行检查,确保遵循内存管理规则。例如,编译器会检查对象的所有权转移是否正确,并发出警告或错误信息。

三,运行期

在运行期,ARC会根据编译器插入的代码来管理对象的生命周期。

1,管理引用计数

  • 引用计数通过retain和release操作来管理。每当对象的引用计数变为零时,dealloc方法会被调用,释放对象的内存。
MyClass *obj = [[MyClass alloc] init]; // retainCount = 1
[obj retain]; // retainCount = 2
[obj release]; // retainCount = 1
[obj release]; // retainCount = 0, dealloc is called

2,处理autorelease池

  • 每当一个对象呗autorelease时,他会被添加到当的auto release池中,池会在每个循环事件末尾被清空,从而释放池中的对象
@autoreleasepool {MyClass *obj = [[[MyClass alloc] init] autorelease];// obj will be released at the end of the autorelease pool block
}

3,解决循环引用

  • 使用weak来打破循环引用。弱引用不会增加对象的引用计数,当对象被释放时,弱应用会被自动值为nil.
@interface MyClass : NSObject
@property (nonatomic, weak) id delegate;
@end

4,动态内存管理

  • ARC 运行期的内存管理是动态的,即在程序运行时根据实际情况管理对象的内存分配和释放

总结

  • 对于ARC 。编译器在代码里适当的地方自动插入 retain / release 完成内存管理(引用计数)。但ARC相对于MRC,又不是在编译时添加retain/release/autorelease这么简单。应该是编译期和运行期两部分共同帮助开发者管理内存。
  • 在编译期,ARC用的是更低层C接口实现的retain/release/autorelease,并不通过OC的消息转发机制,而是直接调用其底层C语言版本API,这样做的性能更好,因为保留及释放操作需要频繁的执行,直接调用其底层的函数能节省很多CPU周期。
  • ARC管理对象生命期的办法是:在合适的地方,插入“保留”及“释放”操作。在方法中创建的对象,在方法中自动插入release;类中的对象,在dealloc方法中释放。
  • 通过retaincount的机制来决定对象是否需要被释放。每次runloop时,都会检查对象的retainCount,如果retaincount = 0时,说明该对象没有地方要继续使用了,可以释放掉了。

补充:

对于__unsafe_unretained修饰符,__unsafe_unretained 和 __weak 相似,是一种弱引用关系。区别在于如果一个对象没有强指针引用,则 __unsafe_unretained 引用不会被置为 nil,而是会变成一个野指针

那有了 __weak,为什么还有 __unsafe_unretained 呢?
__unsafe_unretained 主要是跟 C 语言代码相互。此外,__weak 会消耗一定的性能,使用 __weak 需要检查对象是否被释放,在追踪是否被释放的时候需要追踪一些信息,则使用 __unsafe_unretained 比 __weak 快,消耗 CPU 资源也比 __weak 少。
而且一个对象有大量的 __weak 引用对象的时候,当对象被释放,那么此时就要遍历 weak 表,把表里所有的指针置空,消耗 CPU 资源。
综上所述,当明确知道对象的生命期时,选择 __unsafe_unretained 会有一些性能提升。但是 __unsafe_unretained 也容易引发野指针问题。

自动释放池

1,自动释放池底层怎么实现?

内存里面有栈,栈里面有自动释放池。自动释放池以栈的形式实现:当你创建一个新的自动释放池时,它将被添加到栈顶。当一个对象收到发送autorelease消息时,它被添加到当前线程的处于栈顶的自动释放池中,当自动释放池被回收时,它们从栈中被删除,并且会给池子里面所有的对象都会做一次release操作。
在iOS程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)

2,自动释放池作用
将对象与自动释放池建立关系,池子内调用 autorelease 方法,在自动释放池销毁时销毁对象,延迟 release 销毁时间

3,苹果是如何实现 autoreleasepool 的?
autoreleasepool 以一个队列数组的形式实现,主要通过下列三个函数形成 objc_autoreleasepoolPush、objc_autoreleasepoolPop、objc_autorelease。
前两个函数执行 autorelease 的 push 和 pop 操作,销毁对象执行 release 操作。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Android获取当前屏幕显示的是哪个activity
  • 访问控制系列
  • 【RPC注册发现框架实战】一个简易的RPC注册发现框架
  • Vue.js:如何区分页面关闭和刷新?深入解析与实战
  • mysql命令练习
  • 测试开发面经总结(三)
  • Qt篇——QSqlQueryModel内容居中显示
  • Stable Diffusion:质量高画风清新细节丰富的二次元大模型二次元插图
  • 服务器的80和443端口关闭也能申请SSL证书
  • 容器安全最佳实践和工具
  • 系统架构设计师教程 第3章 信息系统基础知识-3.5 专家系统-解读
  • Vue--Router(路由)
  • Scrapy 核心组件之Spiders组件的使用
  • java在继承的继承上添加新的属性和方法
  • 通过MobaXterm工具远程连接可视化服务器桌面并操控
  • 77. Combinations
  • Fundebug计费标准解释:事件数是如何定义的?
  • HTTP中的ETag在移动客户端的应用
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • node-sass 安装卡在 node scripts/install.js 解决办法
  • PyCharm搭建GO开发环境(GO语言学习第1课)
  • 如何合理的规划jvm性能调优
  • 收藏好这篇,别再只说“数据劫持”了
  • 腾讯视频格式如何转换成mp4 将下载的qlv文件转换成mp4的方法
  • 听说你叫Java(二)–Servlet请求
  • 微服务框架lagom
  • 用element的upload组件实现多图片上传和压缩
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • ​云纳万物 · 数皆有言|2021 七牛云战略发布会启幕,邀您赴约
  • #基础#使用Jupyter进行Notebook的转换 .ipynb文件导出为.md文件
  • $refs 、$nextTic、动态组件、name的使用
  • (09)Hive——CTE 公共表达式
  • (6)设计一个TimeMap
  • (ros//EnvironmentVariables)ros环境变量
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理 第13章 项目资源管理(七)
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .Net Winform开发笔记(一)
  • .net 按比例显示图片的缩略图
  • .NET企业级应用架构设计系列之技术选型
  • .php结尾的域名,【php】php正则截取url中域名后的内容
  • @Resource和@Autowired的区别
  • @Slf4j idea标红Cannot resolve symbol ‘log‘
  • [100天算法】-不同路径 III(day 73)
  • [22]. 括号生成
  • [28期] lamp兄弟连28期学员手册,请大家务必看一下
  • [AI Embedchain] 开始使用 - 全栈
  • [Android] Amazon 的 android 音视频开发文档
  • [Apio2012]dispatching 左偏树
  • [BPU部署教程] 教你搞定YOLOV5部署 (版本: 6.2)
  • [BUUCTF 2018]Online Tool(特详解)
  • [C#]使用深度学习算法opencvsharp部署RecRecNet广角图像畸变矫正校正摄像广角镜头畸变图像
  • [Codeforces] number theory (R1600) Part.11
  • [I2C]I2C通信协议详解(一) --- 什么是I2C
  • [iOS]iOS获取设备信息经常用法