-----<Java培训、Android培训、iOS培训、.Net培训>期待与您交流! --------
OC语言内存管理一
1.内存管理的意义
由于移动设备的内存极其有限,所以每个app的内存也是有限制的,当app所占用的内存较多时候,
系统会发出内存警告,1个app可用内存是被限制的,如果一个app使用内存超过20兆,系统发送
warning消息,回收一些内存。
2.oc内存管理的范围
管理任何继承NSobject的对象,对其他的基本数据类型无效
一.内存管理的原理
1)、对象的所有权及引用计数
对象的所有权
任何对象都可能拥有一个或者多个所有者,只要一个对象至少拥有一个所有者,它就会继续存在
2)对象的引用计数器
每个oc对象都有自己的引用计数器,是一个整数表示对象被引用的次数,即现在有多少东
西在使用这个对象,对象刚被创建时候,默认计数器值为1,当计数器的值变为0时候,对象销毁。
3)引用计数器的作用
判断对象要不要回收的依据,计数器为0则销毁,不为0则存在
4)对引用计数器的操作
给对象发消息,retain消息,计数器+1,该方法返回对象本身
release消息,使计数器-1
retainCount消息,获得当前计数器值
5)对象的销毁
当一个对象的引用计数器为0时,那么它将被销毁,占用的内存被系统回收
当对象被销毁时候,系统会向对象发送一条dealloc消息,
在这里释放相关资源,dealloc就像是对象的遗言
一旦对象被回收了,那么他所占据的存储空间就不可能再利用,坚持使用会导致程序崩溃
二、内存管理的原则
1、只要有人在使用某个对象,那么这个对象就不会被回收
只要你想使用这个对象,那么就应该让这个对象的引用计数器+1
当你不想使用这个对象,就应该让对象的引用计数器-1
2、谁创建谁release
如果你通过alloc,new,copy来创建一个对象,那么你就必须调用release或者autorelease方法
不是你创建的不用你去负责
3、谁retain谁release
只要你调用了retain,无论这个对象时如何生成,你都要调用release
三、野指针问题
1、单个对象的野指针问题
僵尸对象
#import<Foundation/foundation.h>
@interface Person: NSObject
@propery int age;
@end
@implementation Person
@end
int main()
{
//创建对象,引用计数器为1
//通过引用计数器可以判断对象是否需要回收
//使用alloc init方式创建,retainCount =1
Person *p=[[Person alloc] init];
NSlog(@"p->retainCount = %ld",p.retainCount);
[p release]; //release 后 retainCount=0,释放对象空间
[p setAge:20];//这个时候p是一个野指针,不能使用,为了避免使用僵尸对象,p=nil,可以防止调用僵尸对象
}
对象内存泄漏
int main()
{
//创建对象,引用计数器为1
//通过引用计数器可以判断对象是否需要回收
//使用alloc init方式创建,retainCount =1
Person *p=[[Person alloc] init];
NSlog(@"p->retainCount = %ld",p.retainCount);
[p retain];
[p retain];
[p release]; //retainCount =2 内存没有释放 泄漏
}
对象使用过程中被赋值nil 导致内存泄漏
int main()
{
//创建对象,引用计数器为1
//通过引用计数器可以判断对象是否需要回收
//使用alloc init方式创建,retainCount =1
Person *p=[[Person alloc] init];
NSlog(@"p->retainCount = %ld",p.retainCount);
p=nil;
[p release]; //设置对象为nil,实际上让p指向一个特殊地址
}
在函数或者方法中使用retain或者relase不当,造成的问题
- (void)compare:(Person*)person
{
[person retain];
NSlog(@"车在猛跑");
}
Person *p =[[Person alloc]init];
NSlog(@"p->retainCount = %ld",p.retainCount);
[p comper:p];//调用后retain操作+1
[p retain];//此时的对象没有被收回,因为引用计数器没有为0导致内存泄漏
2、多对象野指针问题
#import <Foundation/Foundation.h>
@interface Car : NSObject
-(void)run;
@end
@implementation Car
-(void)dealloc
{
NSLog(@"Car被销毁");
[super dealloc];
}
-(void)run
{
NSLog(@"车正在跑");
}
@end
@interface Person : NSObject
{
Car *_car;
}
-(void)setCar:(Car*)car;
-(Car*)car;
-(void)driver;
@end
@implementation Person
-(void)dealloc
{
NSLog(@"Person被销毁");
[super dealloc];
}
-(void)setCar:(Car*)car
{
_ car = car;
}
-(Car*)car
{
return _car;
}
-(void)driver
{
NSLog(@"开车去拉萨!");
[_car run];
}
@end
第一种野指针错误
Person *p [Person new];
Car *car = [Car new];
//给一辆车
[p setCar:car];
//车销毁了
[car release];
//人驾车继续走
[p dirver]; //因为车销毁了 所以产生野指针错误
[p release]; //人对象销毁
解决方法:
-(void)setCar:(Car*)car
{
_ _car = [car retain];
}
第二种内存泄漏
[p driver];
[p release];
人销毁后,车没有销毁 造成内存泄漏
解决办法:
-(void)dealloc
{
NSLog(@"Person被销毁");
[_car release]; //在人的dealloc方法里做减引用计数器的操作
[super dealloc];
}
第三种内存泄漏
双car对象交换时产生的内存泄漏
Person *person =[[Person alloc]init];
Car *car1 =[[Car alloc]init];
[person setCar:car1];
[person driver];
[car1 release]; //car1 的计数器为1
Car *car2 =[[Car alloc]init];
[person setCar:car2];
[car2 release];
[person release]; //这样 car2 被销毁了 car1 没有被 销毁 造成内存泄漏
解决办法:
-(void)setCar:(Car*)car
{
[_car release];//先释放上一个对象,(注意第一次是向nil发送release消息)
_car = [car retain];
}
第四种 内存泄漏
Person *person =[[Person alloc]init];
Car *car1 =[[Car alloc]init];
[person setCar:car1];
[person driver];
[car1 release];
[person setCar:car1];
[person setCar:car1]; //重复给person 这样就会造成引用计数器增加最后导致car不能被释放,导致内存泄漏
解决办法:
-(void)setCar:(Car*)car
{
//判断_car 存放的是否是 形参对象,如果不是,则执行[_car realease];
if (_car!=car)
{
[_car release];//先释放上一个对象,(注意第一次是向nil发送release消息)
_car = [car retain];
}