什么是内存管理?是指软件运行时对计算机内存资源的分配和使用技术。其最主要的目的就是如何高效、快速的分配,并且在适当的时候释放和回收内存资源。
内存分配
在 iOS 中数据是存在堆和栈中的,然而我们的内存管理管理的是堆上的内存,栈上的内存并不需要我们管理。
- 非OC对象(基础数据类型)存储在栈上
- OC对象存储在堆上
引用计数
引用计数是计算机编程语言中的一种内存管理技术,是指将资源(可以是对象、内存或磁盘空间等等)的被引用次数保存起来,当被引用次数变为零时就将其释放的过程。使用引用计数技术可以实现自动资源管理的目的
MRC的四个法则
- 自己生成的对象,自己持有。
- 非自己生成的对象,自己也能持有。
- 不在需要自己持有对象的时候,释放。
- 非自己持有的对象无需释放。
ARC
ARC其实也是基于引用计数,只是编译器在编译时期自动在已有代码中插入合适的内存管理代码(包括 retain、release、copy、autorelease、autoreleasepool)以及在 Runtime 做一些优化。
所有权修饰符
Objective-C编程中为了处理对象,可将变量类型定义为id类型或各种对象类型。 ARC中id类型和对象类其类型必须附加所有权修饰符。
其中有以下4种所有权修饰符:
- __strong
- __weak
- __unsafe_unretaied
- __autoreleasing
所有权修饰符和属性的修饰符对应关系如下所示:
assign
对应的所有权类型是__unsafe_unretained
copy
对应的所有权类型是__strong
retain
对应的所有权类型是__strong
strong
对应的所有权类型是__strong
unsafe_unretained
对应的所有权类型是__unsafe_unretained
weak
对应的所有权类型是__weak
__strong
表示强引用,对应定义 property
时用到的 strong
。当对象没有任何一个强引用指向它时,它才会被释放
__weak
表示弱引用,对应定义 property
时用到的 weak。弱引用不会影响对象的释放,而当对象被释放时,所有指向它的弱引用都会自动被置为 nil,这样可以防止野指针
__weak 的几个使用场景:
- 在 Delegate 关系中防止循环引用。
- 在 Block 中防止循环引用。
- 用来修饰指向由 Interface Builder 创建的控件。比如:@property (weak, nonatomic) IBOutlet UIButton *testButton;。
ARC 是在 iOS5 引入的,而 __unsafe_unretained
这个修饰符主要是为了在ARC刚发布时兼容iOS4以及版本更低的系统,因为这些版本没有弱引用机制。这个修饰符在定义property时对应的是unsafe_unretained
。__unsafe_unretained
修饰的指针纯粹只是指向对象,没有任何额外的操作,不会去持有对象使得对象的 retainCount +1。而在指向的对象被释放时依然原原本本地指向原来的对象地址,不会被自动置为 nil,所以成为了野指针,非常不安全。
在ARC中做内存管理主要就是发现这些内存泄漏,关于内存泄漏Instrument为我们提供了 Allocations/Leaks 这样的工具用来检测。
这里有一个微信读书团队开源的工具MLeaksFinder,它可以在你程序运行期间,如果有内存泄漏就会弹出提示告诉你泄漏的地方。