day9: 内存管理初级:内存管理的方式、引用计数机制,影响计数的各个方法、dealloc方法、内存管理的基本原则
2015-08-21 19:08
671 查看
内存管理的黄金法则:
黄金法则:每次调用alloc一次,都需要调用release一次,他们两是成对出现的。
内存管理的对象:
所有NSObject下的所有OC对象,都需要做内存管理,基本类型的
内存管理初级
内存常见问题体现在两个方面:内存溢出 和 野指针异常(大部分问题都是野指针异常问题)
内存溢出:没有被释放掉的内存
野指针异常:对象内存空间已经被系统回收,仍然使用指针操作这块内存,野指针异常是程序crash的主要原因,代码量越大的程序,越难找出出现野指针的位置
了解内存管理,能帮我们提升程序性能,大大减少调试bug时间
内存管理的方式:
两种内存管理方式:ARC 和 MRC
Manual Reference Count 人工引用计数(xcode 5 之后就用自动引用计数来管理了,不建议使用MRC,若使用MRC还的手工把ARC调为NO)
Auto Reference Count 自动引用计数(ARC是基于MRC的)
现在xcode可以
引用计数机制
C语言中,使用malloc和free,进行堆内存的创建和释放,堆内存只有正在使用和销毁两种状态
实际开发中,可能会遇到,两个或两个以上的指针使用同一块内存。C语言无法记录内存使用者的个数
OC采用引用计数机制管理内存,当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减,当引用计数为零时,该对象就将释放占有的资源
影响引用计数的方法:
+alloc +1
-retain +1
-copy +1
-release -1
-autorelease -1
dealloc方法
-dealloc是继承自父类的方法,当对象引用计数为0的时候,由对象自动调用
内存管理的基本原则
自动释放池:autoreleasepool的使用
通过autoreleasepool控制autorelease对象的释放
自动释放池中是以栈的形式存在的,在池子释放的时候,会对池子里面所有的对象发送一条release消息,最后进池子的会最先收到release消息
作用:1、把对象放入到自动释放池当中 (如果不在自动释放池中发送release和autorelease是不可以的)
2、对象发送autorelease消息时,这个对象的引用计数不会立即-1,在出池子的时候才会-1;
3、一个对象只能调用一次autorelease,不能多次调用
4、autorelease的一个重要作用是在便利构造器当中使用
5、向一个对象发送autorelease消息,这个对象何时-1取决于autoreleasepool
Person.h
Person.m
main.m
黄金法则:每次调用alloc一次,都需要调用release一次,他们两是成对出现的。
内存管理的对象:
所有NSObject下的所有OC对象,都需要做内存管理,基本类型的
内存管理初级
内存常见问题体现在两个方面:内存溢出 和 野指针异常(大部分问题都是野指针异常问题)
内存溢出:没有被释放掉的内存
野指针异常:对象内存空间已经被系统回收,仍然使用指针操作这块内存,野指针异常是程序crash的主要原因,代码量越大的程序,越难找出出现野指针的位置
了解内存管理,能帮我们提升程序性能,大大减少调试bug时间
内存管理的方式:
两种内存管理方式:ARC 和 MRC
Manual Reference Count 人工引用计数(xcode 5 之后就用自动引用计数来管理了,不建议使用MRC,若使用MRC还的手工把ARC调为NO)
Auto Reference Count 自动引用计数(ARC是基于MRC的)
现在xcode可以
引用计数机制
C语言中,使用malloc和free,进行堆内存的创建和释放,堆内存只有正在使用和销毁两种状态
实际开发中,可能会遇到,两个或两个以上的指针使用同一块内存。C语言无法记录内存使用者的个数
OC采用引用计数机制管理内存,当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减,当引用计数为零时,该对象就将释放占有的资源
影响引用计数的方法:
+alloc +1
-retain +1
-copy +1
-release -1
-autorelease -1
dealloc方法
-dealloc是继承自父类的方法,当对象引用计数为0的时候,由对象自动调用
内存管理的基本原则
自动释放池:autoreleasepool的使用
通过autoreleasepool控制autorelease对象的释放
自动释放池中是以栈的形式存在的,在池子释放的时候,会对池子里面所有的对象发送一条release消息,最后进池子的会最先收到release消息
作用:1、把对象放入到自动释放池当中 (如果不在自动释放池中发送release和autorelease是不可以的)
2、对象发送autorelease消息时,这个对象的引用计数不会立即-1,在出池子的时候才会-1;
3、一个对象只能调用一次autorelease,不能多次调用
4、autorelease的一个重要作用是在便利构造器当中使用
5、向一个对象发送autorelease消息,这个对象何时-1取决于autoreleasepool
Person.h
#import <Foundation/Foundation.h> //想要这个类的实例可以实现copy方法,就要遵守<NSCopying>协议 @interface Person : NSObject<NSCopying> @property(nonatomic,assign)NSString * name; @property(nonatomic,assign)NSInteger age; -(instancetype)initWithName:(NSString *)name andAge:(NSInteger)age; +(instancetype)initWithName:(NSString *)name andAge:(NSInteger)age; -(void)setName:(NSString *)name; -(void)setAge:(NSInteger)age; @end
Person.m
#import "Person.h" @implementation Person @synthesize name = _name,age = _age; //重写父类的方法 //当对象的引用计数从0到1的过程时,由系统来自动调用 -(void)dealloc{ NSLog(@"%@ 对象已销毁",self); //父类的销毁实现方法是必须得调用的 [super dealloc]; } //初始化方法 -(instancetype)initWithName:(NSString *)name andAge:(NSInteger)age{ if (self = [super init]) { _name = name; _age = age; } return self; } //便利构造器 +(instancetype)initWithName:(NSString *)name andAge:(NSInteger)age{ Person * p = [[Person alloc]initWithName:name andAge:age]; //autorelease的一个重要作用是在便利构造器当中使用 return [p autorelease]; } //NSCopying协议当中,必须实现的方法 -(id)copyWithZone:(NSZone *)zone{ Person * p = [[Person allocWithZone:zone]init]; p.name = self.name; p.age = self.age; return p; } //setter方法的内存设置 -(void)setName:(NSString *)name{ if (_name != name) { [_name release]; _name = [name retain]; } } //基本数据类型 不用做内存管理 -(void)setAge:(NSInteger)age{ _age = age; } @end
main.m
#import <Foundation/Foundation.h> #import "Person.h" int main(int argc, const char * argv[]) { //相当于:NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init]; @autoreleasepool { // insert code here... NSLog(@"Hello, World!"); //+alloc Person * p = [[Person alloc]init]; //p.retainCount = 1 //得到p的引用计数(代表有多少指针指向它) NSUInteger pCount = p.retainCount; NSLog(@"p.retainCount = %lu",pCount); //retain p的引用在原来的基础上+1 [p retain]; //p.retainCount = 2 [p retain]; //p.retainCount = 3 //release 让对象的引用计数-1 [p release]; //p.retainCount = 2 [p release]; //p.retainCount = 1 [p release]; //p.retainCount = 0 //message sent to deallocated instance 野指针错误,向一个已经释放掉的对象发送了一条消息 //避免野指针错误的解决方案:[nil release]; //向一个nil发送都不会引起crash,因此当p所指向的堆内存的引用计数变为0时,p=nil;就不会引起程序的crash了 p = nil; //保证p所指向的空间引用计数为0 的时候,在使用的时候运行不崩溃。 NSLog(@"p.retainCount = %lu",p.retainCount); //copy Person * p2 = [p copy]; NSLog(@"p2.retainCount = %lu",p2.retainCount); //打印这两个地址,我们现在是拷贝出来的一个新的对象 NSLog(@"p=%p,p2=%p",p,p2); //因为它遵守了NSCopying协议,所以可以调用copy这个方法 NSString * str = @"zero"; NSString * str2 = [str copy]; //因为在常量区所以引用计数为-1; NSLog(@"str = %ld,str2 = %ld",str.retainCount,str2.retainCount); //autorelease 它的引用计数不会立即-1 Person * p3 = [[Person alloc]init]; [p3 autorelease]; NSLog(@"p3.retainCount = %lu",p3.retainCount); @autoreleasepool { //接收autorelease消息的对象会被放入离它最近的自动释放池 Person * p7 = [[[Person alloc]init]autorelease]; NSLog(@"p7 = %ld",p7.retainCount); //用构造方法 初始化的对象 Person * p8 = [Person initWithName:@"zero" andAge:18]; NSLog(@"p8.retainCount = %ld",p8.retainCount); // [p8 release]; p8 = nil; NSLog(@"p8.retainCount = %ld",p8.retainCount); } //----------copy-------------- //浅拷贝:拷贝的是地址,也就是不会申请一块新的内存空间,源对象的内存空间的引用计数+1; //深拷贝:拷贝的是内容,也就是会申请一块新的内存空间,并把源内存空间中的内容拷贝进去,所以源内存空间的引用计数还是1,新内存空间的引用计数由0变为1;深拷贝拷贝出来的是一个可变的字符串对象。 // 把源对象的内容复制一份,在堆内存申请一块新内存空间,把复制的内容粘贴进去(拷贝的是内容) //浅拷贝 copy NSString * str5 = [[NSString alloc]initWithFormat:@"popo"]; NSString * str6 = [str5 copy]; NSLog(@"str5 = %@ str6 = %@",str5,str6); NSLog(@"str5 = %p str6 = %p",str5,str6); NSLog(@"str5.retainCount = %lu str6.retainCount = %lu",str5.retainCount,str6.retainCount); //深拷贝 mutableCopy NSMutableString * str7 = [str5 mutableCopy]; NSLog(@"str5 = %p,str7 = %p",str5,str7); NSLog(@"str5.retainCount = %lu str7.retainCount = %lu",str5.retainCount,str7.retainCount); NSMutableString * mstr = [[NSMutableString alloc]initWithFormat:@"浩浩"]; NSString * mstr2 = [mstr copy]; NSLog(@"mStr = %p, mStr2 = %p",mstr,mstr2 ); NSMutableString * mStr3 = [mstr mutableCopy]; [mStr3 appendFormat:@"你妹呢?"]; NSLog(@"%@",mStr3); NSLog(@"mStr = %p,mStr3 = %p",mstr,mStr3); NSLog(@"%lu,%lu",mstr.retainCount,mStr3.retainCount); /* 1、只有不可变字符串跟copy才是钱拷贝,其他三种都是深拷贝 2、不管源字符串是否可变,只要用mutableCopy 拷贝出来的字符串都是可变的 */ Person * p5 = [Person initWithName:@"波波" andAge:18]; Person * p6 = [p5 copy]; p6.name = @"浩浩"; p6.age = 20; NSLog(@"p5.retainCount = %lu,p6.retainCount = %lu",p5.retainCount,p6.retainCount); NSLog(@"p5 - %@,%ld",p5.name,p5.age); NSLog(@"p6 - %@,%ld",p6.name,p6.age); //这里的{相当于:[pool release]; } //创建池子 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init]; //创建三个对象放入到池子当中 Person * p4 = [[Person alloc]init]; Person * p5 = [[Person alloc]init]; Person * p6 = [[Person alloc]init]; //向一个对象发送autorelease消息,这个对象何时-1取决于autoreleasepool [p4 autorelease]; [p5 autorelease]; [p6 autorelease]; // [p6 autorelease]; //引用计数为0的时候不能再次释放 //打印这三个对象的地址 NSLog(@"p4 = %@",p4); NSLog(@"p5 = %@",p5); NSLog(@"p6 = %@",p6); //释放池子 [pool release]; return 0; }
相关文章推荐
- 每天进步一点点——Linux文件锁编程flock
- form表单的简单验证onsubmit
- android 组件SeekBar实例
- 博弈
- iBatis调用存储过程的方法
- uva 725Division
- codeforces Gym 100338F Spam Filter 垃圾邮件过滤器(模拟,实现)
- 欢迎使用CSDN-markdown编辑器
- C++: std::string 与 Unicode 如何结合?
- Zoj3201 Tree of Tree 树形DP
- Java中的动态绑定和静态绑定
- 找出字符串中第一个只出现一次的字符
- bootstrap模态框Esc键不关闭
- 03-树3. Tree Traversals Again (25)将先序遍历和中序遍历转为后序遍历
- java 遍历MAP
- hihocoder 1110 正则表达式
- STM32的PWM输入模式设置并用DMA接收数据
- WebService只能在本地使用,无法通过网络访问的解决办法
- Oracle 学习之卸载Oracle 11g
- main函数的参数(一)