黑马程序员------OC 内存管理MRC和autorelease pool
2015-07-30 21:24
603 查看
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
内存管理
1.内存管理概念
由于移动设备的内存机器有限 所以每个被占用的内存也是有限的。不用的内存是余姚回收的,否则程序会崩溃
oc 管理内存的范围: 管理任何继承NSObject的对象,对其他的基本数据类型无效
基本数据类型数据占用的存储空间是固定的 一般存储在栈区。
对象类型是程序运行过程中动态分配的,存储在堆区,内存管理主要是 对堆区的对象 的内存管理
oc内存管理分类:MRC(手动管理内存) ARC(自动管理内存)
2.引用计数器
引用计数器是用来保存当前对象有几个东西在使用它(数字),在对象里有一块专门的空间大小为8个字节来存储
引用计数器的作用 : 用来判断对象是否应该回收(如果对象不等于nil 当引用计数器为0,此时要回收对象的内存空间)
引用计数器的操作
retain 使得引用计数器 +1
release 使得引用计数器 -1
retainCount 得到引用计数器的值
如果一个对象被释放的时候,就会调用“临终遗言”(dealloc方法)
注意:
1)dealloc 方法是NSObject 的,一般我们要重写dealloc方法
2)在dealloc 方法内部,要调用[super dealloc];
注意:永远不要直接通过对象调用dealloc方法。对象一旦被回收不可再用,坚持使用会使程序崩溃
3.内存管理的原则
如果对象有人使用,就不应该回收
如果你想使用这个对象,应该让这个对象retain 一次
如果你不想使用这个对象你应该然然这个对象 release 一次
谁创建谁 release
谁retain 谁release
4.内存管的研究内容
1)野指针 定义的指针变量没有初始化 指向的空间已经被释放
2)内存泄露
{ Person *p=[Person new]; }
p 在栈区 [Person new];在堆区
如果栈区的已经被释放了,而堆区的空间还没有被释放,堆区的空间就被泄露了
注意: p=nil 空指针 没有志向任何店东西的指针 ,给空指针发送消息不会报错。
5.单个对象的内存管理
6.多对象内存管理
set 方法内存管理
原则: 如果在一个类中,有其他类的对象(关联关系)
set方法书写的时候要判断是否是同一个对象,release 旧值,retain新值。
- (void)setDog:(Dog*)dog{
//判断对象是否是原对象
if(_dog =dog){
//release 旧值
[_dog release];
//retain 新值 ,并且赋值给实例变量
_dog =[dog retain];
}
}
7.@property参数
原子性 atomic 对属性加锁,多线程下线程安全,默认值
nonatomic 对属性不加锁 多线程下不安全,但是速度快
读写性 readwrite 生成getter、setter 默认值
readonly 只生成getter方法
set方法处理(内存管理)
assign 直接赋值 默认值
retain 先release原来的值,再retain新值
copy 先release原来的值,再copy新值
什么时候使用retain
在一个类中有关联其他对象的时候,这个时候的@property (nonatomic,retain)
什么时候使用assign 实例变量是最基本的数据的时候
//这个时候会生成 set和get方法的声明和实现
readobnly 只会生成 get方法。默认的时readwrite
@property (nonatomic,assign)int Num;
替换set方法的名称 @property(nonatomic ,setter=isVip:)
[p setVip: ispYES];//--->[p isVip:YES]
替换个get方法的名称 @propery(nonatomic,setter=isVip:,getter=isVip);
@class 的使用
可以简单的引用一个类
@class Dog //类的引入
仅仅是告诉编译器:Dog是一个类;并不会包含Dog这个类的所有内容
具体使用 在.h文件中使用@class引用一个类;在.m文件中使用#import包含这个类的.h文件
#import作用:要把映入的头文件内容拷贝到写#import处 ,如果Person.h文件内容发生变化,此时的所有的Person.h这个头文件的类都要重新编译
使用格式 @class 类名
@clss xxx
含义:是告诉编译器 xxx是一个类 至于有那些属性和方法此处不去检测
好处是:如果xxx文件内容发生了改变,而不需要重新编译
@class 可以解决循环引用的问题
#import 和@class的区别
作用上区别:#import会包含引用类的所有信息(内容),包括引用类的变量和方法
@class仅仅是告诉编译器有这么一个类,具体这个类例有什么信息,完全不知道
效率上的区别
如果有上百的文件都#import了同一个文件,或者这些文件一次被#import,那么一旦最开始的问价稍有改动,后面引用到这个文件的所有类都需要重新编译一边,编译效率非常低
8.autorelease基本使用
自动释放池
1)在ios程序运行过程中,会创建无数个池子,这些池子都是以栈结构(先进后出)存在的。
2)当一个对象调用autorelease时,会将这个对象放到位于栈顶的释放池中
基本方法
1)会将对象放到一个自动释放放池中
2) 当自动释放池子被销毁时,会对池子里的所有对象做一次release
3)会返回对象本身
4)在调用完autorelease方法后,对象的计数器不收影响(销毁时影响)
自动释放池的使用
1)创建自动释放池
@autoreleasepool{
}
2)加入释放池
在自动释放池中
[对象 autorelease];
Person *p = [Person new ];
//创建自动释放池
@autoreleasepool {//自动释放池开始
[p autorelease]//把对象放到自动释放池 ,引用计数器不会变化
}//自动释放池结束 p对象被回收
好处 (1)不再需要关心对象释放的时间 (2)不需要关心社么时候调用release
autorelease是什么原理
autorelease实际上只是把release的调用延迟了,对每个Autorelease ,系统只是把该Object放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有Object会被调用release。
autorelease 的使用注意
1)并不是所有的放到自动释放池中的代码,产生的对象就会自动释放,如果需要释放,必须加入到自动释放池
Person *p =[[Person new] autorelease];
我们只需要在自动释放池代码块中调用autorelease就可以把对象加入到自动释放池
2)如果对象调用;autorelease 但是,调用autorelease的时候,没有在任何一个自动释放池中,此时该对象也不会被加入到自动释放池
自动释放池的栈结构(数据结构),和内存的栈区是不一样的 对象在 位于栈顶的释放池
自动释放池的应用
NSString * str = [NSString stringWithFormat:@"xxxx"];
NSArray * array =[NSArray array]
Person 类方法:
帮我们自动创建对象,并且管理对象的内存(加入到自动释放池)
Person *p =[Person person];
1)创建一个对象 p
2)用完之后,系统把对象释放掉p
Person *p =[[Person alloc] init];
p autorelease;
+(id)person{
//创建对象
return [[[Person alloc] init] autorelease]; //返回对象空间
//能够帮我们把对象给加入到自动释放池
}
内存管理
1.内存管理概念
由于移动设备的内存机器有限 所以每个被占用的内存也是有限的。不用的内存是余姚回收的,否则程序会崩溃
oc 管理内存的范围: 管理任何继承NSObject的对象,对其他的基本数据类型无效
基本数据类型数据占用的存储空间是固定的 一般存储在栈区。
对象类型是程序运行过程中动态分配的,存储在堆区,内存管理主要是 对堆区的对象 的内存管理
oc内存管理分类:MRC(手动管理内存) ARC(自动管理内存)
2.引用计数器
引用计数器是用来保存当前对象有几个东西在使用它(数字),在对象里有一块专门的空间大小为8个字节来存储
引用计数器的作用 : 用来判断对象是否应该回收(如果对象不等于nil 当引用计数器为0,此时要回收对象的内存空间)
引用计数器的操作
retain 使得引用计数器 +1
release 使得引用计数器 -1
retainCount 得到引用计数器的值
如果一个对象被释放的时候,就会调用“临终遗言”(dealloc方法)
注意:
1)dealloc 方法是NSObject 的,一般我们要重写dealloc方法
2)在dealloc 方法内部,要调用[super dealloc];
#import <Foundation/Foundation.h> @interface Person : NSObject @end #import "Person.h" @implementation Person //dealloc方法,是对象临终的遗言方法 //对象被销毁时,会默认的调用该方法 //dealloc方法 是系统根据引用计数器的值,自动调用的 - (void)dealloc{ //先释放子类自己的空间 NSLog(@"person dealloc"); //再释放父类的 [super dealloc]; } @end #import <Foundation/Foundation.h> #import "Person.h" int main(int argc, const char * argv[]) { @autoreleasepool { //用person实例画一个对象 Person *p =[[Person alloc] init ]; //查看有几个拥有者 NSUInteger count =[p retainCount]; NSLog(@"count = %lu",count);//count =1 [p release];//对象要被回收。 使用release 给引用计数器-1 //这时retainCount 为0 对象被回收掉用dealloc 方法 } return 0;
注意:永远不要直接通过对象调用dealloc方法。对象一旦被回收不可再用,坚持使用会使程序崩溃
3.内存管理的原则
如果对象有人使用,就不应该回收
如果你想使用这个对象,应该让这个对象retain 一次
如果你不想使用这个对象你应该然然这个对象 release 一次
谁创建谁 release
谁retain 谁release
#import <Foundation/Foundation.h> @interface Dog : NSObject -(void)eat; @end #import "Dog.h" @implementation Dog -(void)eat{ NSLog(@"狗在吃东西"); } @end #import <Foundation/Foundation.h> #import "Dog.h" int main(int argc, const char * argv[]) { @autoreleasepool { //创建 new alloc init copy Dog *bigYellowDog =[[Dog alloc] init]; Dog*jb =[bigYellowDog retain];// 引用计数器+1 当前值为2 [bigYellowDog release]; //谁retain 谁release //只有保证谁创建谁release,才能保证对象被回收 [bigYellowDog release]; Dog *byd = [[Dog alloc] init]; [byd eat]; //如果一个对象已经被释放了,这个对象就称之为僵尸对象 [byd release]; //这句话佛人情况下不会报错 //如果要报错,要开启僵尸对象检测, //byd指针也就是野指针 [bye eat] [byd retain];//byd已经是僵尸对象了 不能复生 } return 0; }
4.内存管的研究内容
1)野指针 定义的指针变量没有初始化 指向的空间已经被释放
2)内存泄露
{ Person *p=[Person new]; }
p 在栈区 [Person new];在堆区
如果栈区的已经被释放了,而堆区的空间还没有被释放,堆区的空间就被泄露了
注意: p=nil 空指针 没有志向任何店东西的指针 ,给空指针发送消息不会报错。
5.单个对象的内存管理
#import <Foundation/Foundation.h> @interface Dog : NSObject - (BOOL)compareColorWithOther:(Dog*)dog; @end #import "Dog.h" @implementation Dog - (BOOL)compareColorWithOther:(Dog*)dog{ [dog retain];//让传入的对象的引用计数器+1 return YES ; }@end #import <Foundation/Foundation.h> #import "Dog.h" int main(int argc, const char * argv[]) { @autoreleasepool { Dog * d= [[Dog alloc] init]; //1 [d release];//1--》0 //给空指针发送任何消息,都没有效果 //[nil run]; //避免使用僵尸对象方法是,对象释放了以后,给对象赋值为nil //d =nil; //nil 给对象赋值 , Nil类对象 // [d run]; //单个内存泄露问题 //内存泄露情况1 没有错遵守内存故那里原则,创建完之后没有release; //Dog *d = [[Dog alloc] init]; //内存泄露情况2.没有遵守内存管理原则 Dog *d = [[Dog alloc] init];//1 [d retain];//2 [d release]; //retain 完了之后额米有release //内存泄露问题3 不当的使用nil //Dog *d =[[Dog alloc] init];//1 //d=nil; //[d eat] //[d release] //内存泄露情况4 在方法中对传入的对象进行了retain; Dog* d =[[Dog alloc] init];//1 //对象依然被泄露了 [d compareWhithOther:d];//2 [d release]; } return 0; }
6.多对象内存管理
set 方法内存管理
原则: 如果在一个类中,有其他类的对象(关联关系)
set方法书写的时候要判断是否是同一个对象,release 旧值,retain新值。
- (void)setDog:(Dog*)dog{
//判断对象是否是原对象
if(_dog =dog){
//release 旧值
[_dog release];
//retain 新值 ,并且赋值给实例变量
_dog =[dog retain];
}
}
#import <Foundation/Foundation.h> @interface Car : NSObject @property int speed; -(void)run; @end #import "Car.h" @implementation Car - (void)dealloc{ NSLog(@"车被销毁了%d",_speed); [super dealloc]; } -(void)run{ NSLog(@"车以%d 的速度奔向拉萨",_speed); } @end #import <Foundation/Foundation.h> @class Car; @interface Person : NSObject { Car *_car; } @property (assign)NSString * name; //拥有一辆车 -(void)goLasa; - (void)setCar:(Car *)car; -(instancetype)initWithName:(NSString*)name; @end #import "Person.h" #import "Car.h" @implementation Person -(instancetype)initWithName:(NSString*)name{ if (self =[super init]) { _name = name; } return self; } -(void)dealloc{ [_car release ]; NSLog(@"人已经挂了"); //让父类释放 [super dealloc]; } -(void)goLasa{ [_car run]; } - (void)setCar:(Car *)car{ //如果是_car == car 这是同一对象 ,那就不需要relaese if (_car != car) { [_car release]; _car =[car retain]; } } @end #import <Foundation/Foundation.h> #import "Person.h" #import "Car.h" int main(int argc, const char * argv[]) { @autoreleasepool { Person *p =[[Person alloc] initWithName:@"凤姐"]; Car * bmw =[[Car alloc] init]; bmw.speed =200; //给凤姐一辆车 [p setCar:bmw]; //去拉萨 [p goLasa]; [bmw release]; [p goLasa]; //创建新车 Car *byd =[Car new]; byd.speed =100; //凤姐给新车 [p setCar:byd]; [p goLasa]; [byd release]; [p release]; } return 0; } }
7.@property参数
原子性 atomic 对属性加锁,多线程下线程安全,默认值
nonatomic 对属性不加锁 多线程下不安全,但是速度快
读写性 readwrite 生成getter、setter 默认值
readonly 只生成getter方法
set方法处理(内存管理)
assign 直接赋值 默认值
retain 先release原来的值,再retain新值
copy 先release原来的值,再copy新值
什么时候使用retain
在一个类中有关联其他对象的时候,这个时候的@property (nonatomic,retain)
什么时候使用assign 实例变量是最基本的数据的时候
//这个时候会生成 set和get方法的声明和实现
readobnly 只会生成 get方法。默认的时readwrite
@property (nonatomic,assign)int Num;
替换set方法的名称 @property(nonatomic ,setter=isVip:)
[p setVip: ispYES];//--->[p isVip:YES]
替换个get方法的名称 @propery(nonatomic,setter=isVip:,getter=isVip);
@class 的使用
可以简单的引用一个类
@class Dog //类的引入
仅仅是告诉编译器:Dog是一个类;并不会包含Dog这个类的所有内容
具体使用 在.h文件中使用@class引用一个类;在.m文件中使用#import包含这个类的.h文件
#import作用:要把映入的头文件内容拷贝到写#import处 ,如果Person.h文件内容发生变化,此时的所有的Person.h这个头文件的类都要重新编译
使用格式 @class 类名
@clss xxx
含义:是告诉编译器 xxx是一个类 至于有那些属性和方法此处不去检测
好处是:如果xxx文件内容发生了改变,而不需要重新编译
@class 可以解决循环引用的问题
#import 和@class的区别
作用上区别:#import会包含引用类的所有信息(内容),包括引用类的变量和方法
@class仅仅是告诉编译器有这么一个类,具体这个类例有什么信息,完全不知道
效率上的区别
如果有上百的文件都#import了同一个文件,或者这些文件一次被#import,那么一旦最开始的问价稍有改动,后面引用到这个文件的所有类都需要重新编译一边,编译效率非常低
8.autorelease基本使用
自动释放池
1)在ios程序运行过程中,会创建无数个池子,这些池子都是以栈结构(先进后出)存在的。
2)当一个对象调用autorelease时,会将这个对象放到位于栈顶的释放池中
基本方法
1)会将对象放到一个自动释放放池中
2) 当自动释放池子被销毁时,会对池子里的所有对象做一次release
3)会返回对象本身
4)在调用完autorelease方法后,对象的计数器不收影响(销毁时影响)
自动释放池的使用
1)创建自动释放池
@autoreleasepool{
}
2)加入释放池
在自动释放池中
[对象 autorelease];
Person *p = [Person new ];
//创建自动释放池
@autoreleasepool {//自动释放池开始
[p autorelease]//把对象放到自动释放池 ,引用计数器不会变化
}//自动释放池结束 p对象被回收
好处 (1)不再需要关心对象释放的时间 (2)不需要关心社么时候调用release
autorelease是什么原理
autorelease实际上只是把release的调用延迟了,对每个Autorelease ,系统只是把该Object放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有Object会被调用release。
autorelease 的使用注意
1)并不是所有的放到自动释放池中的代码,产生的对象就会自动释放,如果需要释放,必须加入到自动释放池
Person *p =[[Person new] autorelease];
我们只需要在自动释放池代码块中调用autorelease就可以把对象加入到自动释放池
2)如果对象调用;autorelease 但是,调用autorelease的时候,没有在任何一个自动释放池中,此时该对象也不会被加入到自动释放池
自动释放池的栈结构(数据结构),和内存的栈区是不一样的 对象在 位于栈顶的释放池
自动释放池的应用
NSString * str = [NSString stringWithFormat:@"xxxx"];
NSArray * array =[NSArray array]
Person 类方法:
帮我们自动创建对象,并且管理对象的内存(加入到自动释放池)
Person *p =[Person person];
1)创建一个对象 p
2)用完之后,系统把对象释放掉p
Person *p =[[Person alloc] init];
p autorelease;
+(id)person{
//创建对象
return [[[Person alloc] init] autorelease]; //返回对象空间
//能够帮我们把对象给加入到自动释放池
}
快速创建一个学生类初始化年龄 #import <Foundation/Foundation.h> @interface Student : NSObject @property (nonatomic,assign) int age; - (instancetype)initWithAge:(int) age; + (instancetype)studentWithAge:(int)age; @end #import "Student.h" @implementation Student //重写构造方法给年龄初始化 - (instancetype)initWithAge:(int) age{ //初始化父类 判断有没有成功 if (self = [super init]) { //初始化子类。赋值年龄。 _age =age; } return self; } + (instancetype)studentWithAge:(int)age{ return [[[Student alloc] initWithAge:age] autorelease]; } -(void)dealloc{ NSLog(@"Student dealloc"); [super dealloc]; } @end #import <Foundation/Foundation.h> #import "Student.h" int main(int argc, const char * argv[]) { @autoreleasepool { Student *stu =[[Student alloc] initWithAge:18]; NSLog(@"stu.age = %d",stu.age); [stu release]; //快速创建一个对象 给年龄初始化 //1)定义类方法 //2)类方法有参数,传递一个年龄 Student *stu1 =[Student studentWithAge:18]; NSLog(@"stu1.age = %d",stu1.age); } return 0; }
相关文章推荐
- 最好的程序员都是行动派(成功者不是那些明知赚钱之法还要推三阻四的人。成功者知道轻重缓急,善于把握今天) good
- (剑指Offer)面试题46:求1+2+3+....+n
- 程序员常用的编辑器
- Tarena - 职业发展规划之态度
- 知识储备:Java面试知识储备
- 程序员保护眼睛几种方法
- 匆匆那年之Java程序员之最近两周的面试总结:
- 嘉云数据电话面试详解
- 黑马程序员-----OC学习之类与对象
- 教你如何迅速秒杀掉:99%的海量数据处理面试题
- 程序员加入新团队的那些坑
- 黑马程序员------oc foundation结构框架
- 面试题:在字符串中找到第一个不相同的,并输出
- 面试题:空格替换字符
- 面试题—— 从尾到头打印链表
- 【剑指Offer面试题】 九度OJ1519:合并两个排序的链表
- 程序员的恋情
- 黑马程序员--应用:用指针变量作为函数的参数,求出10个数的最大值
- 程序员面试宝典知识点笔记
- 黑马程序员 日记(十)