概述
在iOS开发中主要有量类型的对象,一种是值类型(int、float、strict等基本数据类型),一种就是OC对象,其中值类型是存储在栈上,操作系统会自己管理, OC对象类型存在堆上,是需要我们进行管理的。
iOS的内存管理也就是引用计数。
每一个OC对象内部都有一个整数(4个字节)来存储该对象被引用的次数,称之为引用计数器。如果引用计数器是0,该对象被回收,如果不是0,不回收。总的指导思想就 是这个。
那么引用计数器具体是如何变化的呢?
(1)如果一段代码需要一个对象,这个对象的引用计数就+1;
(2)一段代码使用该对象后,不需要这个对象,这个对象的引用计数就-!;
(3)当引用计数为0,就释放这个对象。
对应的具体操作是:
(1)给对象发retain消息,对象引用计数+1;
(2)给对象发送release消息,对象引用计数-!;
(3)引用计数为0,调用对象的dealloc函数,销毁对象。
管理原则
“谁创建,谁释放,谁引用,谁管理”。具体来说,就是你通过alloc,copy,new,mutableCopy生成并持有对象,通过retain持有对象,在使用完对象之后, 都必须向对象发送release消息。
当一个对象的引用计数为0的时候,就销毁该对象。
自动释放池
在iOS开发中,我们会遇到很多对象只用一次就不需要了,如果我们每次都去手动的释放会很累,iOS提供了一种机制,将这些对象放到一个池子中,在适当的时候, 一起释放这些对象,这里的释放是给池子中的对象发送一个release消息,是池子中的对象的引用计数减小1.
但是,并不是所有的池子中的对象都会被释放,如果池子中的对象引用计数>1,该对象依然不会被释放。
当一个对象被放入到自动释放池,这个对象不会马上被释放,还可以继续使用,在未来某个时间,自动释放池对象收到release消息,才会销毁。
使用方法:
// 方式一
@autoreleasepool {
}
// 方式儿
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init];
//这里写代码
[pool release];
一般使用方式二,效率更高。
自动释放池的生成有两种方式: (1)手动生成,就像上面的代码;
(2)系统在程序事件处理之前自动创建
自动释放池的销毁有两种方式: (1)手动销毁,调用release;
(2)系统在程序时间处理之后自动释放
使用自动释放池需要注意三个问题:
(1)当池子中某些对象的引用计数>1时,对象无法销毁;
(2)自动释放池会在某一时间集中释放,如果操作需要生成的对象较多占用内存空间大,可以使用多个释放池来进行优化。比如在一个循环中需要创建大量的临时变量, 可以创建内部的池子来降低内存占用峰值
例如:
while(i < 10000)
@autoreleasepool {
NSString *str = [NSString stringWithFormat:@"ouput:%d",i];
NSLog(@"%@",str);
i++;
}
(3)autorelease不会改变对象的引用计数
MRC内存管理方式
MRC手动管理内存,就要严格按照“谁创建,谁释放,谁引用,谁管理”的原则。
这里的创建主要是通过alloc,new,copy,mutalblecopy,创建对象,这个时候新建对象的引用计数是1.
引用就是指,你给某个对象发送一个retain消息,对象的引用计数就+1.
使用完毕后,要给对象发送release消息。
同时需要注意的是野指针(悬垂指针),在释放对象的时候,要将指针赋值为nil。
野指针是指该指针指向的内存被释放是收回。
内存泄漏,是指程序没有将不再使用的内存释放,简单说就是没有指针指向某一个未被释放的内存。
另外,需要注意如果一个对象不是用alloc,new,copy,mutalblecopy,创建对象,而是用便利构造器创建的临时对象,这个对象会被立即加入到内部的 自动释放池中,不需要关心何时销毁。
例如:NSMutableArray *arr = [NSMutableArray array];
ARC内存管理方式
ARC相当于系统给我们完成了我们应该去做的事,自动在适当的地方加入release/retain等,在iOS5推出。
ARC修饰符
一共四中修饰符:
__strong :强引用,默认的对象修饰符,持有对象所有权。自动将对象初始化为nil。
__weak:弱引用,不持有对象所有权,主要用于解决循环引用,引用指向的对象释放之后,直接被置为nil,避免悬垂指针。
__unsafe_unretained:主要用于Mac,iOS开发基本用不到。主要兼容iOS5以下的版本。现在基本不用。
__autoreleasing:对象前面有__autoreleasing修饰时,相当于在ARC无效时,调用对象的autoreleasing方法,将对象注册到自动释放池。
方法内部创建的变量,在方法外部使用,要添加__autoreleasing。
但是显示的附加__autoreleasing很少见,通常是隐式的调用,在取得非自己创建并持有的对象时,编译器会检查方法是不是alloc,new,copy,mutalblecopy创建的, 如果不是,就会自动的将返回值的对象注册到autoreleasepool.
例如:id obj = [NSMutableArray array];
总的来说,ARC的strong相当于MRC的retain,weak相当于MRC的release。