iOS内存管理---MRC vs ARC
系列文章目录
iOS基础—Block
iOS基础—Protocol
iOS基础—KVC vs KVO
iOS网络—AFNetworking
iOS网络—NSURLSession
iOS内存管理—MRC vs ARC
iOS基础—Category vs Extension
iOS基础—多线程:GCD、NSThread、NSOperation
iOS基础—常用三方库:Masonry、SDWebImage
iOS基础—定时器:GCD、NSTimer、CADisplayLink
文章目录
- 系列文章目录
- 一、iOS内存管理
- 二、MRC
- 1.alloc/new/copy/mutableCopy
- 2.retain
- 3.release
- 4.autorelease
- 三、ARC
- 1.__strong
- 2.__weak
- 3.__unsafe_unretained
一、iOS内存管理
首先,得明确内存管理的概念,内存管理指的是:
- 分配内存:为应用程序的变量、对象和数据结构在内存中分配空间。
- 使用内存:在程序运行过程中,正确地访问和操作已分配的内存。
- 释放内存:在不再需要某块内存时,归还给操作系统或内存池,避免内存泄漏和碎片化。
根据实现方式,内存管理可以分为手动内存管理和自动内存管理。
- 手动内存管理:由程序员显式地分配和释放内存,例如C语言中的malloc和free。
- 自动内存管理:由运行时系统自动管理内存的分配和回收,例如Java的垃圾回收机制、Objective-C的ARC(Automatic Reference Counting)等。
为什么需要管理内存?
- 预防内存泄漏:
内存泄漏指的是程序在运行期间未能适当地释放不再使用的内存,导致内存逐渐被耗尽,最终可能导致程序崩溃(Out of Memory)或系统性能下降。- 防止悬挂指针:
悬挂指针指的是指向已释放内存的指针,继续访问这些指针会导致不确定行为,可能引起程序崩溃或数据损坏。- 优化内存使用:
没有有效的内存管理,可能会出现内存碎片化,程序执行效率下降等问题。良好的内存管理能够减少碎片化,优化内存利用率,提升程序性能。- 提高程序稳定性:
通过有效的内存管理,可以减少由于内存问题导致的程序崩溃、非预期行为等,增强程序的稳定性和可靠性。- 简化开发过程:
自动内存管理,例如垃圾回收和ARC,能帮助开发者自动处理内存分配和回收,从而减少代码中的错误,简化开发过程。
需要程序员管理的是堆空间,动态分配的内存:
- 栈(Stack):由系统自动管理,用于存储局部变量、函数调用等,具有生命周期短、内存上下文优先的特点,先进先出。
- 堆(Heap):由程序员或运行时手动管理,通常用于动态内存分配,生命周期较长,随机访问和回收。
例如在c++中,可以利用RAII的思想来管理内存,在iOS中,是通过引用计数来完成内存管理的:
在iOS中,引用计数(Reference Counting)是管理内存的关键机制,它用于跟踪对象的引用次数,从而确定对象在什么时候该被释放。引用计数的核心思想是每个对象都有一个计数器,用于记录多少个地方引用了该对象。当引用计数变为零时,对象会被销毁以释放内存。
在Xcode中,我们可以设置iOS管理内存的方式:
二、MRC
手动引用计数(Manual Reference Counting)是开发者需要手动管理对象的引用计数。这包括显式调用retain、release和autorelease方法。
- alloc/init:分配并初始化对象,引用计数为1。
- retain:增加对象的引用计数。
- release:减少对象的引用计数。当引用计数变为0时,内存将被释放。
- autorelease:将对象添加到自动释放池,池被销毁时会调用release。
我们可以通过 retainCount 来获取对象的引用计数:
系统提供的对象,内存管理可能被优化过,所以引用计数打印是-1,官方文档也说明 retainCount 返回的引用计数可能是未定义的,所以用自定义对象来进行实验。
1.alloc/new/copy/mutableCopy
在苹果规定中,使用 alloc/new/copy/mutableCopy 创建返回的对象归调用者所有:
Person *p1 = [[Person alloc] init]; // p1 引用计数为1
Person *p2 = [Person new]; // p2 引用计数为1
Person *p3 = [p1 copy]; // p3 引用计数为1
Person *p4 = [p1 mutableCopy]; // p4 引用计数为1
2.retain
在MRC环境下,retain 方法用于显式增加对象的引用计数。这通常在你希望在多个地方引用一个对象,且每个地方都希望确保对象在自己使用期间不被释放的情况下使用。
另外,当我们使用可变集合类(例如NSMutableArray, NSMutableSet, NSMutableDictionary等)的addObject:方法时,该方法会对添加的对象调用retain,以便持有(retain)该对象。这是集合类的一般行为,用于确保集合内部持有对其对象的强引用,从而防止对象被意外释放。
MRC下 @property 的修饰符:
- 如果在 @property 声明中使用 retain 修饰符,系统会自动为你生成相应的 getter 和 setter 方法,这些方法会包含内存管理代码以便正确处理引用计数。然而,你仍然需要自己在 dealloc 方法中手动释放对象。
- 如果在 @property 后边加上 assign,系统就不会帮我们生成set方法内存管理的代码,仅仅只会生成普通的getter/setter方法,默认什么都不写就是assign。assign 修饰符通常用于基本数据类型(如 int,float 等)以及不需要引用计数管理的对象。
3.release
我们持有一个对象,如果在不需要继续使用该对象时,我们需要对其进行释放(release)。引用计数的持有与释放应该是成对出现的,否则会出现内存泄漏。另外,我们也不能访问某个已经被释放的对象,否则会导致程序崩溃。
4.autorelease
- 在Objective-C中,autorelease是一种用于对象内存管理的方法,特别是在手动引用计数(Manual Reference Counting, MRC)环境中。它主要用于延迟释放对象,即在当前自动释放池(autorelease pool)退出时释放对象,而不是在调用autorelease方法后立即释放。
- 自动释放池(autorelease pool)是一个临时容器,用于存储带有自动释放消息的对象。通常在每个事件循环或程序主运行循环中使用。对象被发送autorelease消息后,被添加到当前的自动释放池中,当自动释放池被销毁时,每个池中的对象都会收到一个release消息。
自动释放池的工作原理
- 加入池中:当一个对象调用 autorelease 方法时,它会被加入当前线程的自动释放池中。
- 池的销毁:当自动释放池销毁时,池中的对象会收到 release 消息,从而适当减小它们的引用计数。
有两种方式创建和管理自动释放池:
- 使用 NSAutoreleasePool(适用于旧代码或不在@autoreleasepool块内的情况):
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// 代码块...
[pool drain];
- 使用 @autoreleasepool 块(推荐的现代方式):
@autoreleasepool {
// 代码块...
}
在执行复杂操作或大量循环时,由于创建了大量的临时对象,这些对象会被添加到自动释放池中。如果池内对象没有被及时释放,可能会导致内存使用增加甚至内存溢出。所以,我们可以在每次循环内创建自动释放池。每次循环迭代结束时,临时对象将被释放,从而避免累积过多未释放的对象导致内存使用激增。
三、ARC
1.__strong
在 ARC(自动引用计数)环境下,Objective-C 提供了几种不同的内存管理修饰符以帮助开发者控制对象的生命周期。其中,__strong 是默认的所有权修饰符。
__strong 的作用:
- 强引用:__strong 修饰的对象在引用存在期间,引用计数会增加,确保对象不会被销毁。
- 自动管理内存:在超出变量作用域时,编译器会自动释放__strong引用计数的对象,无需开发者手动管理内存。
ARC 的工作原理:
ARC(自动引用计数)在编译时会根据代码中的引用情况自动插入 retain 和 release 调用,具体来说:
- 持有对象: 当一个对象被 __strong 修饰符的变量引用时,ARC 插入 retain。
- 释放对象: 当 __strong 修饰符的变量超出作用域或被赋其他值时,ARC 插入 release
2.__weak
__weak 在Objective-C中用来声明一个对象的弱引用,即对该对象的引用不会增加其引用计数。当所引用的对象的引用计数降为0时,会被系统自动销毁,并且所有指向它的弱引用会被自动设置为nil。这在避免循环引用(尤其是在对象之间相互引用的情况下)方面非常有用。
__weak 的作用:
- 弱引用:不会增加引用计数,也不会阻止对象被销毁。
- 自动设置为nil:所引用的对象被销毁时,弱引用会自动设置为nil,防止出现悬挂指针(指向已被销毁对象的指针)。
weak的实现机制:
- 初始化弱引用: 当一个变量以__weak修饰符声明时,系统会在内部记录对象的弱引用。
- 对象销毁时通知: 当一个对象的所有强引用被释放,即将被销毁时,系统会将通知所有指向它的弱引用变量,并将它们设置为nil。
下面是一个循环引用的例子:
用Xcode的 memory graph 来查看对象之间的循环引用,它们无法释放会导致内存泄漏:
用 weak 修饰属性,让属性持有对象的弱引用,就可以正常释放了:
另外需要注意的是,如果一个变量被weak修饰,那么这个变量不能持有对象示例,对象创建完立即被释放,并且编译器会发出警告:
3.__unsafe_unretained
在Objective-C中,除了__strong和__weak,还有另一种所有权修饰符__unsafe_unretained。__unsafe_unretained与__weak类似,它不会增加对象的引用计数,但两者有一个重要的区别:当对象被释放时,__unsafe_unretained指针不会自动设置为nil,从而可能导致悬挂指针(dangling pointer),这会导致访问已释放对象时出现崩溃或未定义行为。
相关文章:

iOS内存管理---MRC vs ARC
系列文章目录 iOS基础—Block iOS基础—Protocol iOS基础—KVC vs KVO iOS网络—AFNetworking iOS网络—NSURLSession iOS内存管理—MRC vs ARC iOS基础—Category vs Extension iOS基础—多线程:GCD、NSThread、NSOperation iOS基础—常用三方库:Mason…...

【数学分析笔记】第1章第1节:集合(2)
这节我自己补了一些内容,要不然听不太懂陈纪修老师讲的 1. 集合与映射 1.3 子集与真子集 假如有 S \textbf{S} S和 T \textbf{T} T两个集合,其中, S \textbf{S} S的所有元素都属于 T \textbf{T} T,则称 S \textbf{S} S是 T \te…...

大话设计模式:七大设计原则
目录 一、单一职责原则(Single Responsibility Principle, SRP) 二、开放封闭原则(Open-Closed Principle, OCP) 三、依赖倒置原则(Dependency Inversion Principle, DIP) 四、里氏替换原则&am…...

利用多商家AI智能名片小程序提升消费者参与度与个性化体验:重塑零售行业的忠诚策略
摘要:在数字化浪潮席卷全球的今天,零售行业正经历着前所未有的变革。消费者对于购物体验的需求日益多样化、个性化,而零售商则面临着如何将一次性购物者转化为品牌忠诚者的巨大挑战。多商家AI智能名片小程序作为一种新兴的数字营销工具&#…...

Scala 闭包
Scala 闭包 Scala 闭包是一个非常重要的概念,它允许我们创建可以在稍后某个时间点执行的功能片段。闭包是一个函数,它捕获了封闭范围内的变量,即使在函数外部,这些变量也可以在函数内部使用。这使得闭包成为处理异步操作、回调和…...

前端JS总结(中)
目录 前言 正文 对象: 分类: 自定义对象: 内置对象: 重点: 常用内置对象: 字符串对象:String 获取字符串长度: 大小写转换: 获取某个字符: 截取字…...

elasticsearch的match_phrase匹配及其可能导致的查询问题
目录 1.match_phrase使用介绍 2.规避可能产生的查询问题 解决方式 一.查询和索引分词器一致,即都使用max_word或者都使用smart 二.使用slop增加匹配的容忍度 3.参考文档 1.match_phrase使用介绍 elasticsearch的match_phrase查询是全文查询,主要用…...

C++快速理解之继承
一、继承和派生 1.是什么? C 中的继承是类与类之间的关系,与现实世界中的继承类似 例如:儿子继承父亲的财产 继承(Inheritance)可以理解为一个类从另一个类获取成员变量和成员函数的过程 例如: 类B继承…...

Node.JS - 基础(Express)
目录 A. 简介 B. 下载,安装 C. 启动服务,查看文件结构 A. 简介 Express 是一个基于 Node.js 平台的极简、灵活的 Web 应用开发框架,它提供了一系列强大的功能来构建 Web 应用程序和 API。 一、Express 的基本特点 简洁的路由系统: Express 的路由系…...

I/O复用
I/O复用使得程序能够同时监听多个文件描述符,这对提高程序的性能至关重要。 举个例子: 就好比你天天玩手机,你妈为了监控你,在你房间安装了一个监控,这个监控可以实时监控你的一举一动,并上传到你妈手机上…...

【验证可用】解决安装SQL Server数据库时,报错“启用 windows 功能 NetFx3 时出错,错误代码:-2146498298......“的问题
目录 背景一. 报错信息1.1 报错的图片信息1.2 报错的文字信息 二. 解决报错2.1 下载 NetFx3.cab 文件2.2 执行命令 三. SQL Server 修复安装 背景 一次在阿里云服务器安装 SQL Server 2012时,系统报错了,导致安装进行不下去…通过在网上查找了多种解决方…...

STM32的SDIO接口详解
目录 1. 定义与兼容性 2. SDIO时钟 3. SDIO命令与响应 4. SDIO块数据传输 5. SDIO控制器的硬件结构 6.代码实现 1.SD初始化 2.测试SD卡的读取 3.测试SD卡的写入 STM32的SDIO(Secure Digital Input/Output,安全数字输入输出)接口是一…...

docker容器常用指令,dockerfile
docker:容器,主要是解决环境迁移的问题,将环境放入docker中,打包成镜像。 docker的基本组成:镜像(image),容器(container),仓库(repository)。镜像相当于类,容器相当于类的实例对象…...

C语言学习笔记 Day11(指针--下)
Day11 内容梳理: 目录 Chapter 7 指针 7.6 指针 & 函数 (1)形参改变实参的值 (2)字符数组作为函数参数 1)合并字符串 2)删掉字符串中空格 (3)指针作为函数返…...

(24)(24.2) Minim OSD快速安装指南(二)
文章目录 前言 6 MinimOSD-extra NG 7 替代硬件 前言 本文简要介绍了如何连接电路板。有关更多详细说明,请参阅 MinimOSD 项目维基(MinimOSD Project wiki)。 6 MinimOSD-extra NG 该项目位于此处(here);文档位于此处(here);支撑线位于此…...

GD32 MCU碰到IIC总线卡死怎么办?
大家在使用MCU IIC通信时,若碰到设备复位或者总线干扰等情况,可能会导致IIC总线卡死,表现上总线上SDA或者SCL其中一根线为低电平,IIC总线一直处于busy状态。此时若代码上一直等待总线空闲,则可能导致软件死机ÿ…...

算法——动态规划:0/1 背包问题
文章目录 一、问题描述二、解决方案1. DP 状态的设计2. 状态转移方程3. 算法复杂度4. 举例5. 实现6. 滚动数组6.1 两行实现6.2 单行实现6.3 优缺点 三、总结 一、问题描述 问题的抽象:给定 n n n 种物品和一个背包,第 i i i 个物品的体积为 c i c_i …...

又是奇瑞,“统一下班时间”过去不久,最近又整新活了...
奇瑞 345 345 可不是奇瑞的汽车型号,而是奇瑞 7 月份会议文章中提出的新策略。 简单来说,要提高加班效率,实现 3 个人干 5 个人活,拿 4 个人的工资,要把员工当成家人一样看待,要对他们的健康幸福负责。 前面…...

ubuntu24.04lts cmake编译 opencv4.5.4 contrib的一些问题
编译之前一定要安装好必须的库,否则即使提示编译成功,调用opencv后也可能会有问题 sudo apt-get update sudo apt-get upgradesudo apt-get install -y g sudo apt-get install -y cmake sudo apt-get install -y make sudo apt-get install…...

大数据面试SQL(三):每分钟在线直播人数
文章目录 每分钟在线直播人数 一、题目 二、分析 三、SQL实战 四、样例数据参考 每分钟在线直播人数 一、题目 有如下数据记录直播平台主播上播及下播时间,根据该数据计算出平台每分钟的在线直播人数。 这里用主播名称做统计,前提是主播名称唯一…...

python中执行mysql操作并将python脚本共享
mysql下载路径: MySQL :: MySQL Community Downloads [root2 ~]# vim py001.py a3 b4 print(ab) print(a**2b**2) [root2 ~]# python py001.py 7 25 [root2 ~]# python3 >>> import random >>> random <module rando…...

HTTP、HTTPS、SOCKS5三种协议特点
在互联网通信中,HTTP、HTTPS和SOCKS5是三种至关重要的协议,它们各自具有独特的特点和应用场景。本文将详细探讨这三种协议的特点,帮助读者更好地理解它们在网络通信中的作用。 一、HTTP协议特点 HTTP(Hypertext Transfer Protoc…...

在ubuntu、centos、openEuler安装Docker
目录 ubuntu、centos、openEuler安装Docker 1.在 Ubuntu 上安装 Docker 1. 1 更新软件包 1. 2 安装必要的依赖 1.3 添加 Docker 的 GPG 密钥 1.4 添加 Docker 仓库 1.5 更新软件包 1.6 安装 Docker 1.7 启动并启用 Docker 服务 1.8 验证安装 1.9 运行测试容器 1.10…...

公共命名空间的例子3
有这样一个句子 用x语言解释[12*3]。 在x语言中,不符合“先乘除后加减”,这个句子应该怎样解释呢? 第一步,进行词法分析,目的是识别出注释和字符串,其中可能包括任意符号,干扰编译过程。 第二步…...

【云存储】SDS软件定义存储,数据存储的类型与技术方案(块/文件/对象,Ceph、RBD等)
【云存储】SDS软件定义存储,数据存储的类型与技术方案(块/文件/对象,Ceph、RBD等) 文章目录 1、分布式存储架构(软件定义存储SDS,超融合基础架构HCI)2、存储类型(块存储,…...

第31课 Scratch入门篇:小画家(舞台上画画)
小画家(舞台上画画) 故事背景: 在舞台上选择画笔和颜色,进行画画 程序原理: 这节课我们继续练习画笔功能,通过画笔功能我们设计一个小画板,碰到哪种颜色画笔就切换成哪种颜色。 开始编程 1、绘制一大一小的黑色圆形,小的命名为画笔,大的圆形命名为black(黑色) 2、鼠…...

QT UI界面之ListView
文章目录 概述源码怎么用代码qt design 小结 概述 本来把布局文件那块写了一遍,但是看看都跟之前那篇差不多,就换了一个稍微有点难度的,也很常用的listview来写了。来看看,有什么好玩的。 源码 先看下源码,如下&…...

freeRTOS互斥量(mutex)
目录 前言 一、互斥量概述 二、互斥量函数 1.创建 2.其他函数 三、优先级反转示例 1.概念 2.代码示例 四、优先级继承 1.概念 2.代码示例 五、递归锁 1.死锁的概念 2.自我死锁 3.函数 4.递归锁代码示例 前言 在之前的信号量中,我们想要实现互斥的…...

基于GeoTools使用JavaFx进行矢量数据可视化实战
目录 前言 一、JavaFx展示原理说明 二、GeoTools的Maven依赖问题 三、引入Geotools相关的资源包 四、创建JavaFx的Canvas实例 五、JavaFx的Scene和Node的绑定 六、总结 前言 众所周知,JavaFx是Java继Swing之后的又一款用于桌面应用的开发利器。当然࿰…...

zabbix的setup无法进入第二步
注意-部署时,报错要看的日志不止一个,php日志的报错也要看的,nginx接收到请求后是转发到php-fpm的 [rootweb01-84-41 ~]# chmod -R 777 /var/lib/php/session chmod: 无法访问"/var/lib/php/session": 没有那个文件或目录 [rootweb…...