*为什么要学习内存管理?
①由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的。
②当我们对Objective-C 的内存管理机制琢磨不透时,编写的程序经常内存泄漏或崩溃。
③当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间。
*Object-C内存管理范围
只管理任何继承了NSObject的对象,不管理其他基本数据类型(int、char、float、double、struct、enum等)。
*手动内存管理解决两个问题
①避免野指针操作
②防止内存泄露
1.认识内存管理基本概念
①僵尸对象:所占用内存已经被回收的对象,僵尸对象不能再使用
②野指针:指向僵尸对象(不可用内存)的指针,给野指针发送消息会报错(EXC_BAD_ACCESS)
③空指针 :没有指向任何东西的指针(存储的东西是nil、NULL、0),给空指针发送消息不会报错
④引用计数器:(int类型,占用4个存储空间)。每个对象都有一个引用计数器,对象诞生时,count=1;当count=0的时候,对象将被销毁(回收)。
⑤retainCount:返回对象引用计数器的值,查看有多少个指针指向这个对象。
⑥retain:返回值为当前对象,count = 引用计数器 + 1;当给对象发送一条retain消息时,引用计数器做加1操作
⑦release:无返回值,count = 引用计数器 - 1;当给对象发送一条release消息, 对象的引用计数器做减1 操作,当引用计数器 = 0,系统自动回收对象。
⑧当引用计数器 = 0时:系统自动给对象发送一条dealloc方法,通知对象将被销毁,其占用内存将被回收,指向其指针没有处理,指针的值还存在则变成野指针。
⑨alloc、new、copy创建新对象,新对象的引用计数器的值默认为1
2.内存管理原则
①在对象中,只要出现了new、alloc、retain,就一定要出现一个release进行配对
②谁创建对象,当其以后不再使用,其release
③谁使用已创建对象,其retain一下,当期以后不再使用,其release
实例示范:
<span style="font-size:12px;">#import <Foundation/Foundation.h> #import "ClassRoom.h" int main(int argc, const char * argv[]) { ClassRoom *student1 = [[ClassRoom alloc]init];//Student1使用了alloc,最后要strdent1调用release NSLog(@"student1使用alloc后,引用计数器为:%zd",[student1 retainCount]); ClassRoom *student2 = [student1 retain];//Student2使用了retain,Student2不再使用,Student2要release NSLog(@"student1使用retain后,引用计数器为:%zd",[student1 retainCount]); [student2 release];//Student2发送release消息,之后Student2不再使用对象 [student1 release];//Student1发送release消息,之后Student1不再使用对象 return 0; }</span>Classroom类重写了dealloc方法如下
- (void) dealloc { NSLog(@"对象被释放"); [super dealloc]; }结果输出:
2015-04-23 21:52:14.914 04-内存管理[689:48749] student1使用alloc后,引用计数器为:1 2015-04-23 21:52:14.915 04-内存管理[689:48749] student1使用retain后,引用计数器为:2 2015-04-23 21:52:14.916 04-内存管理[689:48749] 对象被释放
3.对象组合的内存管理
学生、书都是OC对象,当学生拥有一本书。
学生与书采用组合关系,关键在于学生setBook、dealloc方法的实现。
set模型
- (void)setBook:(Book *)book { if (_book != book) { [_book release]; _book = [book retain]; } }
dealloc模型
- (void)dealloc { [_book release]; [super dealloc]; }
实例示范:
main.m文件
#import <Foundation/Foundation.h> #import "Student.h" #import "Book.h" int main(int argc, const char * argv[]) { Student *student1 = [[Student alloc]init]; student1.name = @"张三"; NSLog(@"学生:%@ 被创建,其引用计数器为:%zd",student1.name,[student1 retainCount]); Book *book =[[Book alloc]init]; book.name = @"读者"; NSLog(@"《%@》被创建,其引用计数器为:%zd",book.name,[book retainCount]); student1.book = book; NSLog(@"《%@》被学生:%@ 使用,其引用计数器为:%zd",book.name,student1.name,[book retainCount]); Book *book1 = [[Book alloc]init]; book1.name = @"亮剑"; NSLog(@"《%@》被创建,其引用计数器为:%zd",book1.name,[book1 retainCount]); student1.book = book1; NSLog(@"《%@》被学生:%@ 使用,其引用计数器为:%zd",book1.name,student1.name,[book1 retainCount]); NSLog(@"%@ 使用《%@》,丢弃《%@》,《%@》引用计数器为:%zd",student1.name,book1.name,book.name,book.name,[book retainCount]); [book1 release];//book1使用alloc一次,所以要release一次 [book release];//book使用alloc一次,所以要release一次 [student1 release];//student1使用alloc一次,所以要release一次 return 0; }Book.h文件
#import <Foundation/Foundation.h> @interface Book : NSObject { @protected NSString *_name; } - (void) setName:(NSString *)name; - (NSString *)name; @end
Book.m文件
#import "Book.h" @implementation Book -(void)setName:(NSString *)name { if (_name !=name) { [_name release]; _name = [name retain]; } } - (NSString *)name { return _name; } -(void)dealloc { [_name release]; [super dealloc]; NSLog(@"《%@》被销毁,释放内存",_name); } @end
Student.h文件
#import <Foundation/Foundation.h> @class Book; @interface Student : NSObject { NSString *_name; Book *_book; } -(void) setName:(NSString *)name; -(void) setBook:(Book *)book; -(NSString *) name; @end
Student.m文件
#import "Student.h" #import "Book.h" @implementation Student - (void) setName:(NSString *)name { if (_name != name) { [_name release]; _name = [name retain]; } } - (void)setBook:(Book *)book { if (_book != book) { [_book release]; _book = [book retain]; } } - (NSString *)name { return _name; } - (void)dealloc { [_name retain]; [_book release]; NSLog(@"%@被销毁,释放内存",_name); [super dealloc]; } @end
结果输出:
2015-04-23 23:13:03.247 04-内存管理[1278:74338] 学生:张三 被创建,其引用计数器为:1 2015-04-23 23:13:03.248 04-内存管理[1278:74338] 《读者》被创建,其引用计数器为:1 2015-04-23 23:13:03.248 04-内存管理[1278:74338] 《读者》被学生:张三 使用,其引用计数器为:2 2015-04-23 23:13:03.248 04-内存管理[1278:74338] 《亮剑》被创建,其引用计数器为:1 2015-04-23 23:13:03.248 04-内存管理[1278:74338] 《亮剑》被学生:张三 使用,其引用计数器为:2 2015-04-23 23:13:03.249 04-内存管理[1278:74338] 张三 使用《亮剑》,丢弃《读者》,《读者》引用计数器为:1 2015-04-23 23:13:03.249 04-内存管理[1278:74338] 《读者》被销毁,释放内存 2015-04-23 23:13:03.249 04-内存管理[1278:74338] 《亮剑》被销毁,释放内存 2015-04-23 23:13:03.249 04-内存管理[1278:74338] 张三被销毁,释放内存4.autorelease的基本用法
②不用考虑何时写release
6.autorelease使用情况
占用内存大的对象,不能随意使用autorelease
7.autorelease常见错误写法
①对象调用autorelease后,又调用release
②连续多次调用autorelease
//常见错误1 @autoreleasepool { Student *stu = [[[Student alloc]init]autorelease]; [stu release]; } //常见错误2 @autoreleasepool { Student *stu = [[[Student alloc]init]autorelease]; Student *stu1 = [stu autorelease]; }
1.set方法内存管理相关的参数
* retain : release旧值,retain新值(适用于OC对象类型)
* assign : 直接赋值(默认,适用于非OC对象类型)
* copy : release旧值,copy新值
2.是否要生成set方法
* readwrite : 同时生成setter和getter的声明、实现(默认)
* readonly : 只会生成getter的声明、实现
3.多线程管理
* nonatomic : 性能高 (一般就用这个)
* atomic : 性能低(默认)
4.setter和getter方法的名称
* setter : 决定了set方法的名称,一定要有个冒号 :
* getter : 决定了get方法的名称(一般用在BOOL类型)
以上实例代码修改如下示范:
main.m文件
#import <Foundation/Foundation.h> #import "Student.h" #import "Book.h" int main(int argc, const char * argv[]) { @autoreleasepool { Student *student1 = [[[Student alloc]init]autorelease]; student1.name = @"张三"; NSLog(@"学生:%@ 被创建,其引用计数器为:%zd",student1.name,[student1 retainCount]); Book *book =[[[Book alloc]init]autorelease]; book.name = @"读者"; NSLog(@"《%@》被创建,其引用计数器为:%zd",book.name,[book retainCount]); student1.book = book; NSLog(@"《%@》被学生:%@ 使用,其引用计数器为:%zd",book.name,student1.name,[book retainCount]); Book *book1 = [[[Book alloc]init]autorelease]; book1.name = @"亮剑"; NSLog(@"《%@》被创建,其引用计数器为:%zd",book1.name,[book1 retainCount]); student1.book = book1; NSLog(@"《%@》被学生:%@ 使用,其引用计数器为:%zd",book1.name,student1.name,[book1 retainCount]); NSLog(@"%@ 使用《%@》,丢弃《%@》,《%@》引用计数器为:%zd",student1.name,book1.name,book.name,book.name,[book retainCount]); } return 0; }
Book.h文件
#import <Foundation/Foundation.h> @interface Book : NSObject @property(retain,readwrite,nonatomic) NSString *name; @end
#import "Book.h" @implementation Book - (void)dealloc { NSLog(@"《%@》被释放,内存回收",_name); [super dealloc]; } @end
Student.h文件
#import <Foundation/Foundation.h> @class Book; @interface Student : NSObject @property(retain,readwrite,nonatomic) NSString *name; @property(retain,readwrite,nonatomic) Book *book; @end
Student.m文件
#import "Student.h" #import "Book.h" @implementation Student - (void)dealloc { [_book release]; NSLog(@"学生:%@被释放,内存回收",_name); [super dealloc]; } @end结果输出:
2015-04-23 23:54:53.554 04-内存管理[1606:87943] 学生:张三 被创建,其引用计数器为:1 2015-04-23 23:54:53.556 04-内存管理[1606:87943] 《读者》被创建,其引用计数器为:1 2015-04-23 23:54:53.556 04-内存管理[1606:87943] 《读者》被学生:张三 使用,其引用计数器为:2 2015-04-23 23:54:53.556 04-内存管理[1606:87943] 《亮剑》被创建,其引用计数器为:1 2015-04-23 23:54:53.556 04-内存管理[1606:87943] 《亮剑》被学生:张三 使用,其引用计数器为:2 2015-04-23 23:54:53.556 04-内存管理[1606:87943] 张三 使用《亮剑》,丢弃《读者》,《读者》引用计数器为:1 2015-04-23 23:54:53.556 04-内存管理[1606:87943] 《读者》被释放,内存回收 2015-04-23 23:54:53.556 04-内存管理[1606:87943] 《亮剑》被释放,内存回收 2015-04-23 23:54:53.557 04-内存管理[1606:87943] 学生:张三被释放,内存回收
原文地址:http://blog.csdn.net/h302849781/article/details/45225807