iOS的内存管理分为MRC和ARC
内存管理原则:
- 只要还有人在使用这个对象,那么这个对象就不会被回收;
- 只要你想使用这个对象,那么就应该让这个对象的引用计数器+1;
- 当你不想使用这个对象时,应该让对象的引用计数器-1;
- 如果你通过alloc,new,copy来创建一个对象,那么你就必须调用release或者autorelease方法;
- 只要你调用了retain,最后都要调用release。
OC内存管理的范围:
- 管理任何继承NSObject的对象,对其他的基本数据类型无效。内存管理主要是对堆区中对象的内存管理。本质原因是:对象存储于堆中,其它局部变量主要存放于栈中,当代码块结束,其中所有局部变量会被回收,指向对象的指针也会被回收,此时对象已经没有指针对象,但还存在于内存中,造成内存泄漏。
@property的参数:
- 读写属性:(readwrite、readonly)
- setter语意:(assign/retain/copy/strong/weak)
- 原子性:(atomic/nonatomic)
各参数意义如下:
引用计数器的作用:
- 引用计数器是判断对象要不要回收的依据(存在一种例外:对象值为nil时,引用计数为0,但不回收空间)。
对引用计数器的操作
- 给对象发送消息,进行相应的计数器操作。
- retain消息:使计数器+1,该方法返回对象本身。
- release消息:使计数器-1,并不代表释放对象
- retainCount消息:获取对象当前的引用计数器值 %ld
三种方法可以增加对象引用计数器的值:
- 显示使用alloc创建一个对象
- 显示使用copy[WithZone:]或者mutableCopy[WithZone:]拷贝对象
- 显示使用retain
对象的销毁
- 当一个对象的引用计数器为0时,那么它将被销毁,其占用的内存被系统回收。
- 在OC中,实例方法dealloc用来释放对象中的实例变量指向的堆空间。
- 当对象被销毁时,系统会自动向对象发送一条dealloc消息,一般会重写dealloc方法,在这里释放相关的资源。
- 一旦重写了dealloc方法就必须调用[super dealloc];,并且放在代码块的最后。
- 一旦对象被回收了,那么他所占据的存储空间就不再可用,坚持使用会导致程序崩溃。
注意:
- 如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不会被回收。
- 任何一个对象,刚生下来的时候,引用计数器都为1。当使用alloc.new.copy创建一个对象时,对象的引用计数器默认为1
自动释放池:
- 自动释放池是OC的一种内存自动回收机制,可以将一些临时变量通过自动释放池统一回收释放
- 每当一个对象接收到autorelease消息时,对象就会被放到自动释放池中,当自动释放池被释放时,他里面的对象会接收到一次release消息
- 当一个对象接收到autorelease消息时,系统会把对象放到最近的自动释放池中。当需要清空自动释放池时,你可以向自动释放池发送一个release消息。
- 简单来说,当向一个对象发送autorelease消息时,对象不会被立即释放。
- 使用autorelease需要注意:首先,发送过多的autorelease消息,就和你发送太多的release一样,当清空自动释放池时,可能会引发内存故障。其次,虽然release消息可以被替换为autorelease,但是出于对系统性能的考虑,可以使用release的地方尽量不要使用autorelease,因为自动释放池所作的工作要比直接使用release多很多。最后,自动释放池的延迟释放机制可能会导致无用的内存消耗。
- 在创建对象时,如果你没有使用alloc,则不需要使用release或者autorelease。但是如果你显示使用了alloc,则你不要忘记使用release或autorelease。
- 当自动释放池释放时,自动释放池中的对象 可能 会被释放。这是因为,当自动释放池释放时,系统会给释放池中的每一个对象发送一个release消息,使得对象的引用计数器的值减1,如果对象引用计数器的值减为0了,则系统会向对象发送dealloc消息彻底销毁对象。
autorelease缺点:
- 不能精确控制对象被销毁的时间,拉长了对象的生命周期,内存处理效率降低。当不确定某个对象什么时候要释放时,或者操作的对象占用内存比较小时,可以用autorelease,但当操作占用内存比较大的对象时,要用release。一般情况下release优先使用。