OC内存管理

Objective-C提供三种内存管理模型:

  1. 自动垃圾回收
  2. 手动引用计数MRC和自动释放池.
  3. 自动引用计数ARC.

Objective-C 2.0 是支持自动垃圾回收机制的.但是iOS运行环境并不支持自动垃圾回收.而且自OS X 10.8及以后也已经不推荐使用了,而是建议使用ARC.
在iOS5之前使用的是手动引用计数简称MRC.iOS5苹果推出了自动引用计数ARC,并且推荐大家使用自动引用计数进行内存管理.自动引用计数ARC就是让编译器来进行内存管理,编译器会在合适的地方帮你插入retain或release,因此不再需要手工输入retain和release代码了.(编译时)
引用计数式内存管理的思想是:

  1. 自己生成的对象,自己持有. 对应 alloc/new/copy/mutableCopy方法.
  2. 非自己生成的对象,自己也能持有. 通过调用retain方法,就能使自己持有.
  3. 不需要自己持有对象时,需要释放. 通过调用release方法,释放自己持有的对象.
  4. 不能释放非自己持有的对象.

在这些思想的指导下,Cocoa 建立了一套明确的内存管理的方法命名规则,在编写用于对象生成或持有的方法时,必须要遵守这些命名规则.以 alloc/new/copy/mutableCopy开头的方法名意味着自己生成并持有对象.在ARC有效时,还要加一条命名规则:以init开头的方法.注意以init开头的方法的规则要比 alloc/new/copy/mutableCopy更严格.该方法必须是实例方法并且必须要返回对象.返回的对象应为id类型或instanceType.该返回的对象并不注册到自动释放池里去.基本上只是对alloc方法返回的对象进行初始化处理并返回该对象.
使用上述方法之外的方法取得的对象是自己不持有的对象,但该对象存在.(根据第四条:不能释放非自己持有的对象.此时如果是MRC环境,就不能调用release方法进行释放,否则崩溃.这种情况在MRC时经常发生.比如UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];从该方法的命名可以看出,取得的对象是自己不持有的,所以如果你对[btn release]将导致奔溃.还有一种情况就是过度release.比如UIButton *btn = [[UIButton alloc] init]; [btn release]; [btn release];btn第一次release时,btn引用的对象就已经被释放了,btn这个指针变量已经变成一个野指针了,如果再release,即是访问这个野指针,这将导致崩溃.)

- (id)allocObject
{
        id obj = [[NSSObject alloc] init];
        return obj;
}
id obj1 = [obj0 allocObject]; //自己生成的对象自己持有
...
[obj1 release]; //所以这里使用完了,需要释放.

以 alloc/new/copy/mutableCopy开头的方法名意味着自己生成并持有对象.因此每次使用都需要时刻记住使用完后要释放对象,但人往往会忘记释放.如果某个方法能够返回一个存在的对象,但该对象却不需要我们自己去释放,这将是一件多么让人兴奋的事!
那么如何返回一个存在但别人不持有的对象呢?
这就需要自动释放池了.
自动释放池( Autorelease Pool )提供了一个可以延迟给对象发送release消息的机制。它的使用场景比如从某方法返回一个对象时。给对象发送autorelease消息,那么该对象就被注册到自动释放池里面去了(这里需要注意的是如果给对象连续发送两条autorelease消息,那么该对象会被注册两次,当池子drain时,该对象将被发送两次release消息,这有可能导致过度release.),等到合适的时候自动释放池会被发送drain消息,此时自动释放池会给池子里面的每个对象都发送release消息,从而释放掉对象.

- (id)object
{
        id obj = [[NSObject alloc] init];
        [obj autorelease]; 
        return obj;
}
id obj1 = [obj0 object]; //取得的对象存在,但自己不持有该对象.所以使用完后,不需要release.

如果想持有,则需发送retain消息.
[obj1 retain];//此时自己就持有了该对象,当不在需要持有时,你有义务释放它.
...
[obj1 release];

dealloc是系统在对象被销毁时自动调用的,不能手动调用!
如果重写了dealloc方法,在MRC环境还需要调用[super dealloc](放在最后一句),但在ARC下禁止调用[super dealloc].

2.自动释放池
自动释放池( Autorelease Pool )提供了一个可以延迟给对象发送release消息的机制。它的使用场景比如从某方法返回一个对象时。给对象发送autorelease消息,那么该对象就被注册到自动释放池里面去了,等到合适的时候自动释放池会被发送drain消息,此时自动释放池会给池子里面的每个对象都发送release消息,从而释放掉对象.
这个"合适的时候"到底是什么时候呢?这就需要runloop了.iOS应用主线程的runloop(NSRunLoop)默认是开启的.当事件发生时,runloop会处理事件,执行我们写的代码.在处理事件之前,它会先创建好一个新的自动释放池对象(NSAutoreleasePool对象),等到处理完这个事件时,runloop会销毁这个NSAutoreleasePool对象,此时自动释放池会给池子里面的每个对象都发送release消息,从而释放掉对象.因此我们可以不用显示创建一个自动释放池.然而,在大量产生autorelease对象时,只要不废弃NSAutoreleasePool对象,那么里面的对象就不能被释放,这个时候就有可能产生内存不足的情况.在这种情况下,有必要在适当的地方生成,持有,废弃NSAutoreleasePool对象.
MRC的写法:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

id obj = [[NSObject alloc] init];

[obj autorelease];

[pool drain];

ARC的写法:

@autoreleasepool
{
    id obj = [NSMutableArray array];
}//对象在这里被释放,并销毁.

注意:ARC对自动释放在运行时做了一些优化.一个对象原本应注册到自动释放池中,但是有些情况下经ARC优化后,这个对象就省略了自动释放池的注册.从而缩短了这个对象的生命周期.所以在ARC下,某个不以 alloc/new/copy/mutableCopy开头的方法,返回的对象我们不应该假定它就是在自动释放池中.
以下是Clang3.9文档的说明
3.2.3 Unretained return values

A method or function which returns a retainable object type but does not return a retained value must ensure that the object is still valid across the return boundary.

When returning from such a function or method, ARC retains the value at the point of evaluation of the return statement, then leaves all local scopes, and then balances out the retain while ensuring that the value lives across the call boundary. In the worst case, this may involve an autorelease, but callers must not assume that the value is actually in the autorelease pool.

ARC performs no extra mandatory work on the caller side, although it may elect to do something to shorten the lifetime of the returned value.
举个例子:

- (void)viewDidLoad 
{
    [super viewDidLoad];

    NSLog(@"--------");
    for (NSInteger i = 0; i < 100000000; i++)
    {
        People *p = [People productPeople];
    }
    NSLog(@"+++++++");
}

这段代码在MRC下将导致内存的急剧增长,并导致应用被系统直接干掉.
说明了-productPeople方法产生的autorelease对象由于自动释放池没被销毁前它里面的对象也不会被释放而导致内存爆涨.
而在ARC下,由于ARC对自动释放池有做优化,所以并没有引起内存的太大变化.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

  • 今天看到一篇不错的文章关于OC内存管理的,转载一下与你共享概述我们知道在程序运行过程中要创建大量的对象,和其他高级...
    niceSYT阅读 443评论 0 2
  • 前言:本篇内容假设您已经对内存管理有了基础的理解。如retain、release、autorelease、auto...
    greatboygirl阅读 660评论 0 3
  • ARC 一、简介 在Objective-C中采用Automatic Reference Counting (ARC...
    伶俐ll阅读 1,640评论 0 3
  • OC内存管理一、基本原理(一)为什么要进行内存管理。由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制...
    ScaryMonsterLyn阅读 510评论 0 3
  • OC内存管理 一、基本原理 (一)为什么要进行内存管理。 由于移动设备的内存极其有限,所以每个APP所占的内存也是...
    iOS_Developer阅读 386评论 0 3