这是我参与「第四届青训营 」笔记创作活动的的第5天
iOS内存管理
iOS 内存管理的核心是管理「(强)引用计数 (Reference Counting)」
在当前代码中,我们基本只用考虑 ARC
Objective C内存管理
- 继承
NSObject对象会分配在堆里面,任何继承NSObject对象都需要进行内存管理 - 多个对象之间相互强引用,导致不能释放,无法让系统回收,如果一个程序占用内存过多,系统可能会强制关闭程序,造成crash,如果提前释放指针,会导致野指针,也会造成crash
- 持有 = retain = 引用计数 +1
- 释放 = release = 引用计数 -1
MRC (Manual Reference Counting)
- 在
OC中,使用引用计数来进行内存管理。每个对象都有一个与其相对应的引用计数器,当持有一个对象,这个对象的引用计数就会递增;当这个对象的某个持有被释放,这个对象的引用计数就会递减。当这个对象的引用计数变为0,那么这个对象就会被系统回收 alloc,new,copy, 或者mutableCopy开头的方法创建的对象,引用计数 = 1// 使用了alloc分配了内存,obj指向了对象,该对象本身引用计数为1,不需要retain id obj = [[NSObject alloc] init]; // 使用了new分配了内存,objc指向了对象,该对象本身引用计数为1,不需要retain id obj = [NSObject new];- 对一个对象发送
retain消息,可以让对象的引用计数 +1,对一个对象发送release消息,可以让对象的引用计数 -1 - 当对象的引用计数为 0 时,即将销毁的时候,系统会向对象发送一条dealloc消息 (不能直接调用 dealloc)
- Autorelease-Pool
- 对象会放到自动释放池,统一释放
autorelease和release的区别:release是马上释放对某个对象的强引用autorelease是延迟释放某个对象
- 在部分场景下,使用Autorelease pool可以降低内存峰值
ARC (Automatic Reference Counting)
retain/release都不用考虑- 只需要初始化的时候
[NSObject alloc] init] - 可以自定义
dealloc
- 只需要初始化的时候
- 只要有一个强指针在内存指向对象,对象就不能释放
- ARC 销毁时机是强引用的个数 = 0,而不是引用计数 = 0
- 默认所有对象变量的指针都是强指针,弱指针需显式声明
__weak Person *p2 = [Person new];
内存管理实例
@property
@property(属性):属性不仅是类的成员变量,还生成了属性的 setter getter方法
- @property 修饰符
strong:拥有属性对象,强持有,只有OC对象才能使用该属性weak: 不拥有属性对象,弱持有,只有OC对象才能使用该属性- 和
strong区别:setter内部会调用copy方法
- 和
assign: 指定setter使用简单赋值- 一般用于simple types, e.g.
基本类型/NSInteger/CGRect default修饰符
- 一般用于simple types, e.g.
weak 销毁与我无关,strong 我销毁它才会销毁
循环引用
浅拷贝 v.s. 深拷贝 可变 v.s. 不可变
深浅拷贝 Shallow/Deep Copy
可变不可变
- 两种类两种行为
- 不可变对象
copymutableCopy
- 可变对象
copymutableCopy
- 不可变对象
不可变到不可变的copy是浅拷贝,其他3种情况是深拷贝
- 内存问题引起 Crash
- 野指针
- 当所指向的对象被提前释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,若操作系统将这部分已经释放的内存重新分配给另外一个进程,而原来的程序重新引用现在的野指针,则将产生无法预料的后果,因为此时野指针所指向的内存现在包含的已经完全是不同的数据
- OOM (Out Of Memory)
- 指的是在 iOS 设备上当前应用因为内存占用过高而被操作系统强制终止
- 野指针