close
当前位置: 物联网在线 > 技术文库 > ios >

理解iOS的内存管理

那些经历过手工管理内存(MRC)时代的人们,一定对 iOS 开发中的内存管理记忆犹新。那个时候大约是 2010 年,国内 iOS 开发刚刚兴起,tinyfool 大叔的大名已经如雷贯耳,而我还是一个默默无闻的刚毕业的小子。那个时候的 iOS 开发过程是这样的:

我们先写好一段 iOS 的代码,然后屏住呼吸,开始运行它,不出所料,它崩溃了。在 MRC 时代,即使是最牛逼的 iOS 开发者,也不能保证一次性就写出完美的内存管理代码。于是,我们开始一步一步调试,试着打印出每个怀疑对象的引用计数(Retain Count),然后,我们小心翼翼地插入合理的 retain 和 release 代码。经过一次又一次的应用崩溃和调试,终于有一次,应用能够正常运行了!于是我们长舒一口气,露出久违的微笑。

是的,这就是那个年代的 iOS 开发者,通常情况下,我们在开发完一个功能后,需要再花好几个小时,才能把引用计数管理好。

苹果在 2011 年的时候,在 WWDC 大会上提出了自动的引用计数(ARC)。ARC 背后的原理是依赖编译器的静态分析能力,通过在编译时找出合理的插入引用计数管理代码,从而彻底解放程序员。

在 ARC 刚刚出来的时候,业界对此黑科技充满了怀疑和观望,加上现有的 MRC 代码要做迁移本来也需要额外的成本,所以 ARC 并没有被很快接受。直到 2013 年左右,苹果认为 ARC 技术足够成熟,直接将 macOS(当时叫 OS X)上的垃圾回收机制废弃,从而使得 ARC 迅速被接受。

2014 年的 WWDC 大会上,苹果推出了 Swift 语言,而该语言仍然使用 ARC 技术,作为其内存管理方式。

为什么我要提这段历史呢?就是因为现在的 iOS 开发者实在太舒服了,大部分时候,他们根本都不用关心程序的内存管理行为。但是,虽然 ARC 帮我们解决了引用计数的大部分问题,一些年轻的 iOS 开发者仍然会做不好内存管理工作。他们甚至不能理解常见的循环引用问题,而这些问题会导致内存泄漏,最终使得应用运行缓慢或者被系统终止进程。

所以,我们每一个 iOS 开发者,需要理解引用计数这种内存管理方式,只有这样,才能处理好内存管理相关的问题。

什么是引用计数

引用计数(Reference Count)是一个简单而有效的管理对象生命周期的方式。当我们创建一个新对象的时候,它的引用计数为 1,当有一个新的指针指向这个对象时,我们将其引用计数加 1,当某个指针不再指向这个对象是,我们将其引用计数减 1,当对象的引用计数变为 0 时,说明这个对象不再被任何指针指向了,这个时候我们就可以将对象销毁,回收内存。由于引用计数简单有效,除了 Objective-C 和 Swift 语言外,微软的 COM(Component Object Model )、C++11(C++11 提供了基于引用计数的智能指针 share_prt)等语言也提供了基于引用计数的内存管理方式。

理解iOS的内存管理

为了更形象一些,我们再来看一段 Objective-C 的代码。新建一个工程,因为现在默认的工程都开启了自动的引用计数 ARC(Automatic Reference Count),我们先修改工程设置,给 AppDelegate.m 加上 -fno-objc-arc 的编译参数(如下图所示),这个参数可以启用手工管理引用计数的模式。

理解iOS的内存管理

然后,我们在中输入如下代码,可以通过 Log 看到相应的引用计数的变化。

- (BOOL)application:(UIApplication *)application          didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  {          NSObject *object = [[NSObject alloc] init];          NSLog(@"Reference Count = %u", [object retainCount]);      NSObject *another = [object retain];      NSLog(@"Reference Count = %u", [object retainCount]);      [another release];      NSLog(@"Reference Count = %u", [object retainCount]);      [object release];    // 到这里时,object 的内存被释放了      return YES;  }  

运行结果:

Reference Count = 1  Reference Count = 2  Reference Count = 1  

对 Linux 文件系统比较了解的同学可能发现,引用计数的这种管理方式类似于文件系统里面的硬链接。在 Linux 文件系统中,我们用 ln 命令可以创建一个硬链接(相当于我们这里的 retain),当删除一个文件时(相当于我们这里的 release),系统调用会检查文件的 link count 值,如果大于 1,则不会回收文件所占用的磁盘区域。直到最后一次删除前,系统发现 link count 值为 1,则系统才会执行直正的删除操作,把文件所占用的磁盘区域标记成未用。

我们为什么需要引用计数
(责任编辑:ioter)

用户喜欢...

电源管理集成电路(PMIC)如何减少这些挑战的影响

在设计具有现场可编程门阵列(FPGA)的系统时,系统设计人员可以获得三个好处:可重编程性,性能可扩展性和快速上市时间。但是,设计师也必须克服挑战。在这篇文章中,我将讨论电源管...


LTC设计说明:带有数字电源系统管理的6A单片同步DC / DC降压转换器

数字电源系统管理(PSM)控制器通常针对高电流负载点(POL)应用。低电流应用,高达6A的负载电流,也可以受益于PSM功能。LTC3815是一款具有数字电源监控功能的6A单片式同步降压型转换器。...


物联网设备的超低功耗管理

据估计,物联网每年将产生数百兆字节(兆亿兆字节)的数据,而这个数字只是在增加。一般家庭对这个数字的贡献数量预计到2020年将增长五倍。创建数据并不需要太多的计算能力,因为可以...


苛刻的环境挑战电源管理

基于数据的预测建模为工业系统监控提供了极大的节约成本的可能性,这将进一步促进工厂和制造业的自动化,并协助翻新运输和能源传输基础设施。对数据的需求将要求工业界用与物联网(...


[原创] TI TIDA-01501 450W高效电源参考设计

TI公司的TIDA-01501是450W高效AC/DC转换器,AC输入85V-265V,多路DC输出12-V/5-V/3.3-V,最大输出功率450W.设计电路包括前端连续模式...


管理混合云环境的5个要点

大多数企业都意识到了采用云计算的好处,那么企业将业务迁移到混合云管理平台的最佳实践是什么呢?...


unity静态批处理原理理解

1、静态批处理的时间点 1)在游戏导出的时候,在player setting中勾选static batching,这样在导出包的时候就进行批处理,导出来的包就会比较大 2 ) 在游戏场景中勾选场景物体的static选项,在加...


鱼与熊掌兼得,既要云服务创新也要管理传统网络

对于很多企业来说,软件即服务(SaaS)等云计算解决方案的效率显著提高、资本支出显著降低。但是真正从云技术中寻...


[原创] T PWD13F60高密度600V功率驱动器解决方案

ST公司的PWD13F60是集成了栅极驱动器和四个N沟功率MOSFET(双半桥配置)高密度功率驱动器.功率MOSFET有320 mΩ的RDS(on)和600...


[原创] ADI AD8452模拟前端控制器和SMPS PWM驱动器解决方案

ADI公司的AD8452是单一的硅芯片平台,集成了精密模拟前端控制器和开关电源(SMPS)脉宽调制器(PWM)驱动器,以实现大规模电...