【为什么要进行内存管理】
由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,这时需要回收一些不需要再继续使用的内存空间,比如回收一些不再使用的对象和变量等。
管理范围:任何继承NSObject的对象,对其他的基本数据类型无效。
本质原因是因为对象和其他数据类型在系统中的存储空间不一样,其它局部变量主要存放于栈中,而对象存储于堆中,当代码块结束时这个代码块中涉及的所有局部变量会被回收,指向对象的指针也被回收,此时对象已经没有指针指向,但依然存在于内存中,造成内存泄露。
【内存管理】
内存管理就是确保申请的内存能够得到合理及时的释放
1、忘记释放一个堆空间,称为【内存泄漏】
2、使用已经释放的内存,称为【提前释放】
3、多次释放同一堆空间,称为【重复释放】
【困境】
1、释放一个堆空间,需要确保所有指向该空间的指针都不再使用
2、释放一个堆空间,需要确保指向同一空间的指针只释放一次
3、模块化操作时,哪个模块负责释放将成为巨大的难题
4、多线程操作时,没有办法确定哪个线程最后结束
【解决】
采用类似于聊天室的计数方式。第一个人开始聊天时创建聊天室,并将计数值设置为1。当多一个人加入聊天室时,将计数值加1;当一个人离开聊天室时,将计数值减1,计数值减到0时释放聊天室。
其实就是确保聊天室中的人数与计数值相等。
【结论】
在创建对象时引用计数默认为1,当多一个指针指向该对象时将计数值加1;当少一个指针指向对象时将计数值减1,计数值减到0时释放对象。
其实就是确保指向对象的指针数等于计数值,每一个OC对象都有自己的引用计数,表示对像被引用的次数,即表示现在有多少东西在使用这个对象。
一、手动内存管理
Manual Reference Counting,简称MRC
【关闭ARC】
1、工程 —> gar
2、Yes —> No
【相关操作】
1、获取对象的引用计数
NSUInteger count = [dog retainCount];
2、使对象的引用计数加1
//将对象的引用计数加1,并返回该对象的地址
//平白无故的retain是不允许
JYDog *dog2 = [dog retain];
3、使对象的引用计数减1,减到0时释放对象
[dog2 release];
dog2=nil;//该语句经常被省略,但是要确保dog2以后不再使用。
4、析构方法
//析构方法,在对象释放时自动调用
- (void)dealloc
{
NSLog(@"dog 对象即将释放");
[super dealloc];
}
当一个对象的引用计数器为0时,那么它将被销毁,其占用的内存被系统回收。
当对象被销毁时,系统会自动向对象发送一条dealloc消息,一般会重写dealloc方法,在这里释放相关的资源,dealloc就像是对象的“临终遗言”。一旦重写了dealloc方法就必须调用[super dealloc],并且放在代码块的最后调用(不能直接调用dealloc方法)。
一旦对象被回收了,那么他所占据的存储空间就不再可用,坚持使用会导致程序崩溃(野指针错误)。
【黄金法则】
1、凡是用alloc/new/retain/copy(开头)/mutableCopy(开头)等创建的对象,都需要调用release/autorelease进行释放。
2、谁写alloc,谁写release;哪个类创建,哪个类释放
【注意事项】
1、对象的子对象需要在析构方法中释放
2、在指针转移时,应先释放就对象,然后指向新对象
3、数组的内存管理,
NSMutableArray *ary = [[NSMutableArray alloc] init];
NSString *str1 = [[NSString alloc] initWithUTF8String:"123"];
//将一个对象添加到数组中,会自动retain
[ary addObject:str1];
//当数组释放时,会向数组中的每个对象发送一个release消息
//[ary release];
[str1 release];
//NSLog(@"str1:%lu", str1.retainCount);
//从数组中获取一个对象,对象并没有retain,在使用时应确保对象没有释放
//可以获取retain一次
//建议短时间(数组释放前)内可以不用retain
NSString *str2 = [ary[0] retain];
[ary release];
NSLog(@"str2:%lu", str2.retainCount);
[str2 release];
4、[[JYClass alloc] init] <==> [JYClass new]
5、(mutable)copy基本上只有在NSString上
【自动释放】
以前不是关键字,是一个类NSAutoreleasePool,可以将需要释放的对象存放在其中(类似于一个数组),等池释放时将其中的对象各释放一次,也叫延迟释放。
现在为了配合ARC改成关键字@autoreleasepool
【说明】
1、一定要结合自动释放池
2、对象的引用计数不会直接减1,等池释放时才会减1
【自动释放原则】—— 非用不可的时候
1、类方法创建的对象
2、getter方法中[[_name retain] autorelease]