了解内存管理的方式:
-
为什么要使用内存管理?
随着Retina屏幕的出现,程序对素材的要求也有所提高,素材的像素能力需要是非Retina屏素材像素的4倍,无疑会对内存造成一定压力,更容易达到内存上限,除了内存溢出造成crash之外,程序里的野指针也是造成App crash的主要原因。程序开发中,程序crash多数是由于内存问题导致的,因此掌握内存管理是分许元必备的技能。 -
内存管理的方式:
垃圾回收(gc)
ARC(Auto Reference Count)
MRC(Manual Reference Count)
-
垃圾回收:
程序只需要开辟内存空间,不需要用代码显示地释放,系统来判断哪些空间不再被使用,并回收这些内存空间,以便再次分配。整个回收的过程不需要写任何代码,由系统自动完成垃圾回收。Java开发中一直使用的就是垃圾回收技术。 -
ARC:
Auto Reference Count,自动引用技术:iOS5.0的编译器特性,它允许用户只开辟空间,不去释放空间。它不是垃圾回收!它的本质还是MRC,只是编译器帮程序员默认加了释放的代码。 - iOS支持两种内存管理方式:ARC和MRC
- MRC的内存管理机制是:引用计数
掌握内存管理各个关键字的作用:
- 在引用计数中,每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递增。当引用计数到零时,该对象就将释放占有的资源。
-
影响引用计数的方法:
+alloc
-retain
-copy
-release
-autorelease
- +alloc:开辟内存空间,让被开辟的内存空间引用计数变为1。这是由0到1的过程
- -retain:引用计数加1,如果内存空间之前引用技术为1,retain之后变为2,如果引用计数是5,retain之后变为6.
- -copy:把某一内存区域的内容拷贝一份,拷贝到新的内存空间里去,被拷贝区域的引用计数不变,新的内存区域的引用技术为1.
- -release:引用技术减1,如果内存空间之前引用技术为4,releaes之后变为3,如果之前引用技术为1,release之后变为0,内存被统一回收。
- -autorelease:未来的某一时刻引用技术减1。如果内存之前引用计数为4,autorelease之后仍然为4,未来某个时刻会变成3。
-
copy方法:
跟retain不同,一个对象想要copy,生成自己的副本,需要实现NSCopying协议,定义copy的细节(如何copy)。如果类没有接受NSCopying而给对象发送copy消息,会引起crash。 -
copy方法的实现:
- (id)copyWithZone:(NSZone *)zone
{
Person *person = [[Person allocWithZone:zone] init]; person.name = self.name; person.age = self.age; return person; }
掌握内存管理的基本原则:
- 引用计数的增加和减少相等,当引用技术降为0之后,不应该再使用这块内存空间
- 凡是使用了alloc、retain或者copy让内存的引用技术增加了,就需要使用release或者autorelease让内存的引用技术减少。在一段代码内,增加和减少的次数要相当。
-
autoreleasepool的使用
通过autoreleasepool控制autorelease对象的释放。
向一个对象发送autorelease消息,这个对象何时释放,取决于autoreleasepool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Person *p = [[Person alloc] init]; // retainCount为1
[p retain]; // retainCount为2
[p autorelease]; // retainCount为2 未来的某个时刻释放
[pool release];
NSLog(@"%lu", (unsigned long)[p retainCount]);
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];和[pool release];就像一个一对括号,[xxx autorelease];必须写在两者之间。
- [xxx autorelease];出现在两者之间,pool就会把接收autorelease的对象保存起来(以栈的方式,把对象亚入栈)
- 当[pool release];的时候,pool会向之前保存的对象逐一发送release消息(对象出栈,越晚autorelease的对象,越早接收release消息)
- 在iOS5之后,不在推荐使用NSAutoreleasePool类,使用@autoreleasepool{}替代,之前写在NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];和[pool release]; 之间的代码,需要写在@autoreleasepool{}的大括号里。出现大括号,自动释放池才向各个对象发送release消息