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 操作。

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

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

相关文章

自主升级,平稳过渡!麒麟信安保障长沙市智慧交通发展中心CentOS迁移无忧

长沙市智慧交通发展中心围绕综合交通运输协调体系的构建,实施交通运行的监测、预测和预警,面向公众提供交通信息服务,开展多种运输方式的调度协调,提供交通行政管理和应急处置的信息保障。 该中心目前数据日交换量超2亿条&#x…

React Native: 构建原生级移动应用的跨平台框架

在移动开发领域,React Native作为一个创新的框架,允许开发者使用JavaScript和React来构建原生移动应用。这意味着开发者可以编写一次代码,同时在iOS和Android平台上运行,而不需要为每个平台单独开发。本文将探讨React Native的基本…

urllib的使用

urllib时python的一个内置库,一共包含四个模块 1. request-请求 这是最基本的HTTP请求模块,可以模拟请求的发送。就像在浏览器输入URL,按下回车一样,只需要给库方法传入URL以及额外的参数,就可以模拟实现发送请求的过…

社交电商的新篇章:AI智能名片O2O商城小程序与传统微商的区别与融合

摘要 在数字经济蓬勃发展的今天,互联网技术的革新正以前所未有的速度重塑着商业格局。传统微商模式,尽管在初期借助社交媒体迅速崛起,但因其固有的局限性,如产品质量不一、营销手段单一、信任机制脆弱等,逐渐暴露出诸…

postman实现接口关联

假如接口2依赖接口1里面的某个字段的值,那么在接口1的Tests里使用代码对这个字段进行提取设置,代码:JSON.parse(responsebody)赋值给一个变量var jsondata,然后将jsondata里面的数据提取出来并设置成公共变量供其他接口进行关联使用&#xff…

HTML-VUE页面调用android 客户端网络请求并返回数据

在Html-- Vue页面调用Android客户端网络请求并返回数据,通常需要通过WebView与Android客户端的JavaScript接口进行交互。以下是一个简化的示例: 在Android端,创建一个JavaScript接口: public class WebAppInterface {Context mC…

Qt程序图标更改以及程序打包

Qt程序图标更改以及程序打包 1 windows1.1 cmake1.1.1 修改.exe程序图标1.1.2 修改显示页面左上角图标 1.2 qmake1.2.1 修改.exe程序图标1.2.2 修改显示页面左上角图标 2 程序打包2.1 MinGW2.2 Visual Studio 3 参考链接 1 windows 1.1 cmake 1.1.1 修改.exe程序图标 获得一个…

重要的单元测试

👽System.out.println(“👋🏼嗨,大家好,我是代码不会敲的小符,目前工作于上海某电商服务公司…”); 📚System.out.println(“🎈如果文章中有错误的地方,恳请大家指正&…

docker将Java、vue、nginx打进镜像(涉及容器打成镜像)

一、背景 一个项目更新需要打成镜像包发布。 dockerspringboot.jarvue静态文件nginx 本文不讲安装docker,安装好安装,镜像源稍微麻烦点 二、操作 抄作业原文 传送门 按照上文拉取centos7,然后将需要的东西直接打进脚本,这样最简单&#…

云原生、Serverless、微服务概念

云原生(Cloud Native) 云原生是一种设计和构建应用程序的方法,旨在充分利用云计算的优势。云原生应用程序通常具有以下特征: 容器化:应用程序和其依赖项被打包在容器中,确保一致的运行环境。常用的容器技…

【Git分支管理】分支2种合并模式

目录 0.回顾 1.ff模式 2.no-ff模式 3.ff模式转no-ff模式 先提交再合并再提交 0.回顾 前面介绍了两种情况总结如下: master没有修改提交,在dev中修改提交,master和dev合并顺利master修改提交的同时dev也修改提交了,产生合并…

【数据结构】高效解决连通性问题的并查集详解及Python实现

文章目录 1. 并查集:一种高效的数据结构2. 并查集的基本操作与优化2.1 初始化2.2 查找操作与路径压缩2.3 合并操作与按秩合并 3. 并查集的应用3.1 判断连通性3.2 计算连通分量 4. 并查集的实际案例4.1 图的连通性问题4.2 网络连接问题 5. 并查集的优缺点5.1 优点5.2…

每天一个数据分析题(四百三十一)- 卡方检验

在列联表分析中,下列不能用卡方检验的是() A. 多个构成的比较 B. 多个率的比较 C. 多个均值的比较 D. 以上都不是 数据分析认证考试介绍:点击进入 题目来源于CDA模拟题库 点击此处获取答案 数据分析专项练习题库 内容涵盖…

HTTP——POST请求详情

POST请求 【传输实体文本】向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在POST请求体中。POST 请求可能会导致新的资源的建立或已有资源的修改。 场景: 1. 提交用户注册信息。 2. 提交修改的用户信息。 常见的…

BernNet Learning Arbitrary Graph Spectral Filters via Bernstein Approximation

发表于:neurips21 推荐指数: #paper/⭐⭐ 设定:在本文中,h是过滤器. bernstein 多项式逼近(这个证明有点稀里糊涂的,反正我觉得一点点问题,可能因为我水平低) p K ( t ) : ∑ k 0 K θ k ⋅ b k K ( t ) ∑ k 0 K f ( k K ) ⋅ ( K k ) ( 1 − t ) K − k t k . p_K(t):…

构建加速器:在Gradle中利用构建缓存提升性能

构建加速器:在Gradle中利用构建缓存提升性能 Gradle作为当今流行的构建工具,提供了多种方式来优化构建速度和效率。其中,Gradle构建缓存是一项强大的功能,它允许重用先前构建的输出,从而显著减少构建时间。本文将深入…

大数据hive表和iceberg表格式

iceberg: https://iceberg.apache.org/ iceberg表,是一种面向大型分析数据集的开放表格式,旨在提供可扩展、高效、安全的数据存储和查询解决方案。它支持多种存储后端上的数据操作,并提供 ACID 事务、多版本控制和模式演化等特性&#xff0c…

【常见开源库的二次开发】基于openssl的加密与解密——Base的编解码(二进制转ascll)(二)

目录: 目录: 一、 Base64概述和应用场景 1.1 概述 1.2 应用场景 二、Base16 2.1 Base16编码 2.2 Base16编解码 三、Base64 四、OpenSSL BIO接☐ 4.1 Filter BIOs: 4.2 Source/Sink BIOs: 4.3 应用场景: 4.4 具体使用&…

Spark核心技术架构

Apache Spark是一个开源的分布式计算系统,它提供了一个快速、通用和易于使用的集群计算环境。Spark 支持多种编程语言,如 Scala、Java 和 Python,并针对大规模数据处理进行了优化。以下是 Spark 技术架构的详细简述: 1. 核心组件…

设计模式学习(二)工厂模式——抽象工厂模式

设计模式学习(二)工厂模式——抽象工厂模式 背景抽象工厂模式优点与缺点参考文章 背景 现在我需要开发一个相机操作模块,它可能在Windows下运行,也可能在Linux下运行。由于在厂家提供的SDK中,Windows下的SDK和Linux下…