OC基础——内存管理



1、什么是内存管理
1>移动设备的内存及其有限,每个app所能占用的内存是有限的;
2>当app所占用的内存比较多时,系统会发出内存警告,这时要回收一些不需要再使用的内存空间。
注意:栈:存放局部变量(所占用的内存会自动销毁);
         堆:存放OC对象(所占的内存不会自动销毁,需手动销毁)

2、引用计数器:每个对象都有一个引用计数器,是一个整数,占4个字节,用于计算对象被引用的次数,即有多少人在使用当前对象。当引用计数器值为0时,表示无人在用,对象所占用的内存会被系统回收,从内存中移除。只要计数器不为0,对象就不会被回收,除非整个程序已经退出。当产生一个新对象时,对象的引用计数器默认是1。

引用计数器的操作:
1>  给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身);
2>  给对发送一条release消息,可以使引用计数器值-1;
3> 可以给对象发送retainCount消息获得当前引用计数器值。

3、对象的销毁
1> 当一个对象的引用计数器值为0时,那么它将会被销毁,其占用的内存会被系统回收。
2> 当一个对象被销毁时,系统会自动向对象发送一条dealloc消息。
3> 一般会重写dealloc方法,在这里释放相关资源,dealloc就像消息的遗言。需注意:dealloc是系统自动调用的,一般不能直接调用。
4> 一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用。
5> 不要直接调用dealloc方法。
eg:
<span style="font-family:Microsoft YaHei;font-size:14px;">@implementation Peson
-(void)dealloc
{
    NSLog(@"Person对象被回收");
    [super dealloc];
}</span>

4、僵尸对象、野指针
1> 僵尸对象:当对象的引用计数器变为0时,对象就会被回收,意味着当前存储空间 不能用,此时这个对象就变成了“僵尸对象”。
2> 野指针:指向僵尸对象(不可以内存)的指针成为野指针。
注意:给野指针发送消息会野指针错误,报错提示:EXC_BAD_ACCESS
3> 空指针:没有指向任何对象的指针(nil、NULL、0),给空指针发送消息不会报错。

5、多对象内存管理
特点:1> 只要有人在用某个对象,那么这个对象就不会被回收;
          2> 只要你想用这个对象,就让对象的计数器加1(让对象做一次retain操作);
          3> 当你不再使用这个对象时,就让对象的计数器减1(让对象做一次release操作)。
总之:谁创建,谁release,谁retain,谁release。

6、 set方法的内存管理
1> 只要调用了alloc,必须有release(或autorelease),如果对象不是通过alloc创建的,则不需要release。
2> setf方法的代码规范:
基本数据类型:
-(viod)setAge:(int)age
{
    _age = age;
}
oc对象类型:
-(void)setWithCar:(Car *)car
{
   if(car != _car)  //判断传进来的是不是新对象
  {
     [_car release]; //获取新对象时,需要对旧对象做一次release
     _car = [car retain];//需要对新对象做一次retain。
  }
}
3> dealloc方法的代码规范
     1)一定要[super dealloc],并且放在最后面;
     2)对self(当前对象)所拥有的其他对象做一次release。
-(viod)dealloc
{
   [_car release]; //当人会回收了,代表车也不用了,所以需要对车做一次release。
   NSLog(@"Person对象被回收!");
   [super dealloc];
}
7、property的内存管理
1> 默认情况下,在声明中@property Book *book;会自动生成setter和getter方法,但都只是赋值操作,没有retain操作。
但若写成@property (retain)Book *book;在生成的set方法里面,会自动release旧值,retain新值。
2>property的参数:
    set方法内存管理相关的参数:
    1) retain :release旧值,retain新值(适用于OC类型的对象);
    2) assign:直接赋值(默认),适用于非OC对象类型;
    3) copy:release旧值,copy新值。
    多线程管理
    1) nonatomic:性能高(一般就用这个)
    2)atomic:性能低。
8、循环引用
@class
1>对于循环依赖关系,比如A类import B类,B类同时也import A类

这种情况下代码会报错,此时如果将其中一个import改成@class,就不会报错了。
2> @class的作用:声明一个类,仅仅告诉编译器,某个名称是一个类。eg:@class Person,
需注意:
1)@class仅仅声明这个类,不会将此类的方法和成员变量导入,当真正用到这个类的时候,在.m文件中#import这个类
2)可以循环声明,如A声明B,B声明A。
3> @class与#import的区别
      1)#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;  @class方式只是告诉编译器在A.h文件中的B类只是一个类,具体这个类有什么信息,这里不需要知道,等文件中真正要用到的时候,才会去查看B类中的信息。
      2)如果有上百个头文件都#import了同一个文件,或者这些文件依次被#improt,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,降低效率。(A->B B->C C->D……,一旦A变动,则后面都需要重新编译)。
      3) 在.m实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类。
循环retain
概念:比如A对象retain了B对象,B对象retain了A对象,这样会导致A对象和B对象永远无法释放。
解决方案:当两端相互引用时,应该一端用retain、一端用assign。
eg:
//car
@property (nonatomic,retain)Person *person;

//Person
@property (nonatomic,assign)Car*car
9、autorelease
1> 作用:1)给某个对象发送一条autorelease消息时,就会将这个对象加到一个自动释放池中, 当自动释放池销毁时,会给池子里面的所有对象发送一条release消息。
                2)调用autorelease方法时并不会改变对象的计数器,并且会返回对象本身。
需注意:当自动释放池被销毁时,对象不一定被销毁,只是做一次release操作
eg:

@autoreleasepool
{ //代表开始创建了自动释放池
    Book *book = [[[Book alloc] init] autorelease];//必须存在自动释放池,才能写autorelease。
}//代表销毁自动释放池
需注意:1>autorelease方法返回对象本身;
2>autorelease 会将对象放到一个自动释放池中;
3> 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
4> 调用完autorelease方法后,对象的引用计数器值不变。
 2>autorelease的好处:不用再关心对象的释放时间,即不用关心什么时候调用autorelease。
      autorelease的缺点:不能精确的控制内存销毁的时间。所以尽量用release,便于精确控制。
3> 使用注意:1)占用内存较大的对象不要随便用autorelease。
                       2)占用内存较小的对象(比如int  float double等)使用autorelease,没太大影响。
4> @autoreleasepool
{
     Person *p = [[[Person alloc]init]autorelease]auturelease;

注意:以上代码会发生野指针错误,写两次autorelease意味着当池子销毁时,会对对象做两次release操作。所以不能写两次autorelease。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值