OC 基础之----内存管理总结

一 一个对象的内存管理

1.    管理范围:任何继承了 NSObject 的对象.

2.    对象的基本结构:每个 OC 对象都有自己的引用计数器,是一个整数,表示”对象被引用的次数”,(一个引用计数器占4个字节),当对象计数器减为0的时候,对象会被回收.

3.    每个 OC 对象内部专门有4个字节的存储空间来存储引用计数器.

4.    引用计数器的作用:

1⃣ 当使用 alloc,new 或 copy 创建一个新对象的时候,新对象的引用计数器默认为1.

2⃣ 当一个对象的引用计数器值为0的时候,对象占用的内存就会被系统回收.换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占的内存就不可能被回收,除非整个程序已经退出.

5.    计数器的操作

1⃣ 给对象发送一条 retain 消息,可以使引用计数器+1(retain 方法返回对象本身)

2⃣ 给对象发送一条 release 消息,可以使引用计数器值-1

3⃣ 可以给对象发送 retainCount 消息获得当前引用计数器值

6.    对象的销毁

1⃣ 当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收

2⃣ 当一个对象被销毁时,系统会自动向对象发送一条 dealloc 消息

3⃣ 一般会重写 dealloc 方法,在这里释放相关资源, dealloc 就像对象的遗言

4⃣ 一旦重写了 dealloc 方法,就必须调用[super dealloc],并且放在最后面调用

5⃣ 不要直接调用 dealloc 方法

6⃣ 一旦对象被回收了,它占用的内存就不在可用,坚持使用会导致程序崩溃(野指针错误)

7⃣ 指向僵尸对象的指针(不可用内存),所占用的内存已经被回收的对象,僵尸对象不能再使用

8⃣经典错误  EXC_BAD_ACCESS:访问了一块坏得内存(已经被回收,已经不可用的内存),即野指针错误.解决方案,将指针清空(p = nil)

9  OC中不存在空指针错误,给空指针发送消息,不报错.

指向僵尸对象的指针,叫做野指针.给野指针发送消息会报错.

没有指向任何东西的指针(存储东西是 nil,NULL,0),给空指针发送消息不会报错.

 

 二  对多对象的内存管理

1.想使用某个对象,就应该让对象的计数器+1 (让对象做一次 retain 操作)

2.你不想在使用某个对象,就应该让对象的计数器-1(让对象做一次 release)

3.谁 retain, 谁 release

4.谁 alloc,谁 release.

5.内存管理代码规范:

 1⃣ 只要调用了 alloc 必须有 release(autorelease)

 2⃣ set 方法的代码规范

基本数据类型:直接复制

-  (void)setAge:(int)age

{

_age = age;

}

 OC 对象类型:

-  (void)setCar: (Car *)car{

//1.先判断是不是新传进来的对象

if(car != _car){

2.对旧对象做一次release

[_car release];

3.对新对象做一次retain

_car = [carretain];

}

}

3⃣ dealloc 的代码规范

一定要[super dealloc],而且放到最后面;

对 self 所拥有的其他对象做一次 release

- (void)dealloc{ [_car release];  [super dealloc];}

 6.对象如果不是通过 alloc 产生的,就不需要 release

1.    基本原理

1⃣ 由于移动设备的内存极其有限,所以每个 APP 所占的内存也是限制的,当 app 所占的内存较多时,系统就会发出警告,这时需要回收一些不需要再继续使用的内存空间,比如回收一些不在使用的对象和变量等.

 2⃣ 管理范围:任何继承 NSObject 的对象,对其他的基本数据类型无效.

 3⃣ 本质原因是因为对像和其他数据类型在系统中的存储空间不一样,其他局部变量主要存放在栈中,而对象的指针也被回收,此时对象已经没有指针指向,但依然存在于内存中,造成内存泄露.

2.    对象的基本结构

每个 OC 对象都有自己的引用计数器,是一个整数表示对象被引用的次数,即现在有多少东西在使用这个对象,对象刚被创建时,默认计数器值为1,当计数器的值变为0时,则对象销毁.

在每个 OC 对象内部,都专门有4个字节的存储空间来存储引用计数器.

3.    引用计数器的作用

判断对象要不要回收的唯一依据就是计数器是否为0,若不为0则存在.

4.    操作

给对象发送消息,进行相应的计数器操作.

Retain 消息:使计数器+1,该方法返回对象本身

Release 消息:使计数器-1(并不代表释放对象)

retainCount 消息:获得对象当前的引用计数器值

5.    对象的销毁

1⃣ 当一个对象的引用计数器为0时,那么它将被销毁,其占用的内存被系统回收.

2⃣ 当对象被销毁时,系统会自动向对象发送一条 dealloc 消息,一般会重写 dealloc 方法,在这里释放相关的资源, dealloc 就像是对象的”临终遗言”.一旦重写了 dealloc 方法就必须调用[super dealloc]; 并且放在代码的最后调用(不能直接调用 dealloc 方法)

一旦对象被回收了,那么它所占的内存空间就不在可用,坚持使用会导致程序崩溃(野指针错误).

6.    相关概念和使用注意

野指针错误:访问了一块坏得内存(已经被回收,不可用的内存),指向僵尸对象的指针.

僵尸对象:所占的内存已经被回收的对象,僵尸对象不能被使用.

空指针:就是没有指向任何东西的指针(nil,0,NULL),给空指针发送消息,是不会报错的.

注意:不能使用[p retain]让僵尸对象起死回生

7.    通过引用技术管理内存的方式有两种方式: MRC 和 ARC

1⃣  MRC:(Manual Reference Count),手动引用计数器,由开发人员通过引用计数去管理内存

2⃣  ARC:(Automatic ReferenceCount),自动引用计数,由系统自动通过引用计数管理内存

ARC是基于 MRC创建出来的;

8.    使用 alloc 生成对象的时候,会将引用计数由0变为1.

打印引用计数,使用 retainCount; 打印 retainCount 的时候,一定要在 MRC环境下.

[person release]; person = nil, 将对象置为空指针()

9.    autoreleasepool 自动释放池,autorelease 必须下载自动释放池中.

Autorelease的实质是:对一个对对象使用 autorelease 操作,这个对象的引用的引用计数不会立即减1,对象会被放到自动释放池里面,等这个池子结束时,会对对象的引用计数一次减1.

系统会将 autoreleasepool 中的对象保存起来,(以栈的方式,把对象压入栈),在 autorelepool 运行结束的时候,会向保存的对象逐一发送 release 消息,

10. 创建一个数组,将创建的对象添加到数组中,在向数组添加元素的时候,(数组会对添加的对象做引用计数器加1的操作),如果使用便利构造器创建的类型,不需要进行手动释放,系统会自动释放;如果使用 alloc 方法创建的类型,在结束时候需要手动的释放创建的对象.

11. Copy的使用

1⃣ 对像使用 copy 的前提是,这个类遵循 NSCopying 协议,而且必须实现协议内的方法

2⃣  copy 方法的实现

在类的. M文件中,实现协议必须要实现的方法:

 深拷贝:返回一个新的对象,跟原来的对象所占空间大小相同,而且空间的内容也相同

-      (void)copyWithZone:(NSZone *)zone{

Person *p = [[Person allocWithZone:zone]init];

P.age = self.age;

P,name = self.name;

Return p;

}

浅拷贝:拷贝的是地址.

12. New: 申请内存将 retainCount 从0变为1.

13. 总结内存管理的原则:

1⃣ 加1操作的(alloc,new,retain,copy)

2⃣ 减1操作的:(release,autorelease)

3⃣ 一旦对象的引用计数器为0;系统会自动调用 dealloc 方法,之后就不能再对对象进行操作了

4⃣ 谁 alloc, 谁 release, 自己创建的对象,自己管理

  九 内存管理的原则

1.    有人在使用对象,对象就不能被回收;不想使用对象的时候,让对象的引用计数器减1.

2.    谁创建,谁释放(如果通过 alloc,new,copy 创建一个对象,必须调用 release 或者 autorelease 方法进行释放)

3.    谁 retain, 谁 release(只要你调用了 retain, 就需要使用 retain 进行释放)

4.    autorelease 的使用注意事项:

1⃣ @autoreleasepool 可以随意创建,也可以嵌套使用

2⃣ 如果把一个对象重复加到自动释放池,会出错([p1 autorelease], [p1 autorelease]),第一次释放正确,第二次释放错误.

3⃣ 操作内存比较大得元素的时候,不要随便发的使用,操作内存比较小的对象的时候可以使用

   十 内存管理的高级

1.    retain中 setter 方法最严谨的写法(release 旧值, retain 新值)(适用于 OC 对象类型)

if(_name != name){

[_name release];

_name = [name retain];

}

判断传入的值与原来的值是否相等,如果不相等,对旧址做一次 release操作,对新值做一次 retain 操作,然后在进行赋值.

在 setter 方法进行赋值的时候,需要进行判断:

1⃣ ([b1 release]; [p1 setBook:b1])这个时候再操作就会因为操作僵尸对象引起Crach

2⃣ 避免重复赋值相同数据.



1.    Copy 中 setter 方法最严谨的方法(release 旧值, copy 新值)

if(_name != name){

[_name release];

_name = [name copy];

}

2.    Assign 主要用于基本数据类型和遵循了协议的实例变量,使用内存组 assign 进行修饰

3.    当完全重写一个setter getter 方法的时候,一定要把属性的实现部分写上@ synthesize name = _name;

4.    便利构造器的内存管理

1⃣ 方式1:Person *per = [[Person alloc]initWithName:name age:age];

[p release];  error对象已经释放,没有办法返回

return [p autorelease]; 是管理便利构造器的完美解决方法,既不会造成内存泄露,也不会产生野指针.

2⃣ 方式二:

return [[[Person alloc]initWithName:name age:age]autorelease];

5.    便利构造器的内存管理:

a.    便利构造器方法内部使用 autorelease 释放对象

b.    通过便利构造器生成的对象不用释放

c.     在便利构造器中,内存自动管理,谁创建,谁管理

d.    不能在创建的便利构造器中添加 release 操作

6.    内存管理总结:

a.    当你占用对象的时候,我们要让引用计数器加1,做一次 retain 操作

b.    当你不想占用某个对象的时候,要让它的引用计数器减1,(也就是做一次 release)

c.     谁 alloc, 谁 release, 便利构造器要用 autorelease

d.    cmd + shift + b 用来检测是否有内存泄露

7.    dealloc 是 NSObject 的一个实例方法,与alloc 对应,用于回收开辟的内存空间;这个方法在引用计数为0的时候,由系统自动调用,通常我们在 dealloc中释放类的实例变量.

注意事项:永远不要手动调用 dealloc; 在 dealloc 方法的最后一行,必须要写[super dealloc];


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值