黑马程序员-----oc语言学习笔记之内存管理一

-----<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];
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值