共计 1800 个字符,预计需要花费 5 分钟才能阅读完成。
一、原起
iOS 的内存相关知识是我们开发 iOS APP 的基石之一,也是面试中必然会问的问题。内存知识的融会贯通,与及内存相关问题的解决,是 iOS 开发者必须要掌握的。
二、iOS 内存相关知识点
2.1 iOS 的内存管理方式
iOS 的内存管理机制为 引用计数。早期使用的是MRC(手动引用计数),需要开发者自己编写引用计数的代码,对开发者是一个不小的挑战,而且容易出错,给开发者也带来了不小的苦恼。
苹果公司为了让开发者更好的专注于开发,在 2011 年的 iOS5 版本开始引入了ARC(自动引用计数),帮助开发者进行内存的管理。
ARC 的工作原理大致是:当我们编译源码的时候,编译器会分析源码中每个对象的生命周期,然后基于这些对象的生命周期,来添加相应的引用计数操作代码。
2.2 内存泄漏
内存泄漏(memory leak):是指申请的内存空间使用完毕之后未回收。
一次内存泄露危害可以忽略,但若一直泄漏,无论有多少内存,迟早都会被占用光,最终导致程序 crash。(因此,开发中我们要尽量避免内存泄漏的出现)
内存泄漏的现象:程序的可用内存越来越少,最终导致程序崩溃。
2.3 内存溢出
内存溢出(out of memory):是指程序在申请内存时,没有足够的内存空间供其使用。
内存溢出的现象:程序直接重启或者崩溃。
2.4 内存泄漏的检测
- 第一种:静态分析方法(Analyze)
- 第二种:动态分析方法(Instrument 工具库里的 Leaks)
2.5 常见的发生内存泄漏的场景
2.5.1 AFHTTPSessionManager
AFHTTPSessionManager 发生内存泄漏的解决方案在此。
2.5.2 ViewController 中的 NSTimer
VC 中使用 NSTImer
的示例如下:
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(updateTime:)
userInfo:nil
repeats:YES];
理由:这时 target: self,增加了 ViewController 的 retain count,
即self强引用 timer,timer 强引用 self,造成循环引用。
解决方案:在恰当时机调用 [timer invalidate]
即可。
2.5.3 ViewController 中的 delegate
对于 delegate 我们一般都是使用 weak 修饰,这个不多作解释。
2.5.4 ViewController 中 Block
在我们日常开发中,如果 block 使用不当,很容易导致内存泄漏。
理由:如果 block 被当前 ViewController(self) 持有,这时,如果 block 内部再持有 ViewController(self),就会造成循环引用。
解决方案:在 block 外部弱化 self,再在block 内部强化已经弱化的weakSelf。
三、iOS 内存管理
iOS 的内存管理机制是:引用计数 。MRC 基本上已经绝迹,现在主流的还是 ARC。系统的内存分为 栈内存 和堆内存 , 栈内存
是系统管理的,不需要开发者插手,开发者管理的主要是 堆内存。
当下我们使用 ARC(自动引用计数) 进行管理的是 堆内存。
3.1 内存管理的原则
当我们使用 alloc、new 创建对象之后,对象的引用计数为 1.
当我们对对象进行 strong、copy 操作之后,对象的引用计数 +1.
当我们对对象进行 mutableCopy
操作之后,生成了一份对象的拷贝,而不是简单的引用计数 +1
,这个需要特别注意。
当我们不再持有对象时,对象的引用计数 -1。
当对象的引用计数为 0 时,对象会被释放掉,进行内存的回收。
3.2 需要开发者自己管理的内存
core foundation框架主要提供的是 C 语言的 API,不属于ARC 管理的范畴,所以使用 core foundation 创建的对象,需要开发者自己进行内存的管理,在对象使用完毕之后进行内存的回收,否则会进行内存的泄漏。
3.3 内存峰值
开发中,对于一些 大循环 如果把控不好,会出现 内存峰值过高 的情况,这个时候我们需要在循环的内部合理的使用 autoreleasepool 进行内存峰值的管理。
总结
本文主要是对 iOS 内存相关的知识点进行了一个归纳总结。
- iOS 的内存管理方式为 引用计数 ,分为MRC 和ARC。
- 内存泄漏的原因。
- 内存溢出的原因。
- 内存泄漏的排查方法,静态排查 & 动态排查。
- 内存泄漏的常见场景。
- 内存峰值的管理。