OC中的MRC与ARC机制

简介

Objective C的引用计数理解起来很容易,当一个对象被持有的时候计数加一,不再被持有的时候引用计数减一,当引用计数为零的时候,说明这个对象已经无用了,则将其释放。

引用计数分为两种:

手动引用计数(MRC)
自动引用计数(ARC)


MRC

手工管理内存计数

当创建对象时,初始引用计数为1
retain 计数加1
release 计数减1
当计数为0后会调用dealloc方法,对象准备被摧毁

// MRC代码
NSObject * obj = [[NSObject alloc] init]; //引用计数为1
//不需要的时候
[obj release] //引用计数减1
//持有这个对象
[obj retain] //引用计数加1
//放到AutoReleasePool
[obj autorelease]//在auto release pool释放的时候,引用计数减1

虽说这种方式提供了面向对象的内存管理接口,但是开发者不得不花大量的时间在内存管理上,并且容易出现内存泄漏或者release一个已被释放的对象,导致crash。

对象引用和自动释放池

自动释放池可以帮助追踪需要延迟一些时间释放的对象。通过自动释放池发送drain消息,自动释放池会被清理,对象会被释放。

自动释放池并不包含实际的对象,而是只包含对象的引用,对像将在自动释放池清理的时候被释放。

程序中使用foundation, UIKit,AppKit框架的类时,首先需要创建一个自动释放池,这样来自这些框架的类才会创建并返回自动释放的对象,需要在程序中使用@autoreleasepool指令。

@autoreleasepool {
    class *a = [[class alloc] init];

    [a release];
}

当程序执行到autorelease块的末尾时,系统会释放池。这将影响到所有发送过autorelease消息并被添加到自动释放池中的对象,会对池中的每个对象发送release消息。当这些对象的引用计数减至0时,会发送出dealloc消息,并且他们的内存会被释放。

实际上,任何用以alloc ,copy , mutablecopy 和 new 为前缀的方法创建的对象都不会被自动释放。在这种情况下可以说你拥有这个对象。当你拥有一个对象时,需要在使用完这些对象后负责释放这些对象的内存。主动给这些对象发送release消息,或者给对象发送autorelease消息将对象加入到自动释放池中。

@autoreleasepool {
    class *a = [[class alloc] init];

    [a release];
}

//或
@autoreleasepool {
    class *a = [[class alloc] init];
    [a autorelease];
}

当在一个函数中生成一个对象,并将这个对象做为返回值的情况下,可以通过以下方法延迟对象的释放。

class *a =[[[class alloc] init] autorelease];
或
return [a autorelease];

手工内存管理规则的总结

  • 如果需要保持一个对象不被销毁,可以使用retain。在使用完对象后需要使用release进行释放。

  • 给对象发送给release消息并不会必须销毁这个对象,只有当这个对象的引用计数减至0时,对象才会被销毁。然后系统会发送dealloc消息给这个对象用于释放它的内存。

  • 对使用了retain或者copy,mutablecopy,alloc或new方法的任何对象,以及具有retain 和copy特性的属性进行释放需要覆盖dealloc方法,使得在对象被释放的时候能够释放这些实例变量。

  • 在自动释放池被清空时也会为自动释放那的对象做些事情。系统每次都会在自动释放池被释放时发送release消息给池中的每个对象。如果池中的对引用计数降为0,系统会发送dealloc消息摧毁这个对象。

  • 如果在方法中不再需要用到这个对象,但需要将其返回,可以给这个对象发送autorelease消息用于标记这个对象延迟释放。autorelease消息并不会影响到对象的引用计数。

  • 当应用终止时,内存中的所有对象都会被释放,不论她们是否在自动释放池中。

  • 当开发cocoa或者ios应用程序时,随着应用程序的运行,自动释放池会被创建和清空。在这种情况下,如果要使自动释放池被清空后自动释放对象还能够存在,对象需要使用retain方法,只要这些对象的引用计数大于发送autorelease消息的数量,就能够在池清理后生存下来。


ARC

自动引用计数 ARC

后来,Apple对iOS/Mac OS开发引入了ARC。使用ARC,开发者不再需要手动的retain/release/autorelease. 编译器会自动插入对应的代码,再结合Objective C的runtime,实现自动引用计数。

比如如下ARC代码:

NSObject * obj;
{
    obj = [[NSObject alloc] init]; //引用计数为1
}
NSLog(@"%@",obj);

等同于如下MRC代码

NSObject * obj;
{
    obj = [[NSObject alloc] init]; //引用计数为1
    [obj relrease]
}
NSLog(@"%@",obj);

ARC可以避免手工引用计数的一些潜在陷阱。不必担心返回了方法内创建的对象。编译器会管理好对象内存,通过生成正确的代码去自动释放或保持返回的对象。

ARC所适用数据类型

在Objective C中,有三种类型是ARC适用的:
block
objective 对象,id, Class, NSError*等
由attribute((NSObject))标记的类型。
像double *,CFStringRef等不是ARC适用的,仍然需要手动管理内存。

Tips: 以CF开头的(Core Foundation)的对象往往需要手动管理内存。

最后,我们在看看ARC中常见的所有权关键字,

  • assign对应关键字__unsafe_unretained, 顾名思义,就是指向的对象被释 放的时候,仍然指向之前的地址,容易引起野指针。
  • copy对应关键字__strong,只不过在赋值的时候,调用copy方法。
  • retain对应__strong
  • strong对应__strong
  • unsafe_unretained对应__unsafe_unretained
  • weak对应__weak。

ARC背后的引用计数主要依赖于这三个方法:

retain 增加引用计数
release 降低引用计数,引用计数为0的时候,释放对象。
autorelease 在当前的auto release pool结束后,降低引用计数。

在Cocoa Touch中,NSObject协议中定义了这三个方法,由于Cocoa Touch中,绝大部分类都继承自NSObject(NSObject类本身实现了NSObject协议),所以可以“免费”获得NSObject提供的运行时和ARC管理方法,这就是为什么适用OC开发iOS的时候,你的类要继承自NSObject。

既然ARC是引用计数,那么对应一个对象,内存中必然会有一个地方来存储这个对象的引用计数。

在默认情况下所有对象的指针变量都是使用强引用,默认情况下属性@property使用的时assign,当我们需要将属性设为强引用时需要设strong 当 需要设弱引用则使用weak

@property (strong) NSString * a;
@property (weak ) NSString * a;

强引用与弱引用需要注意的地方
当存在循环引用的情况下,如果双方都是强引用,那么会导致一个问题,存在一种循环保持的状态,导致内存无法释放,解决这个问题就可以使用弱引用,当内存中弱引用所指向的强引用被释放后,弱引用不再被使用也会被释放。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值