【译】苹果官方手册:高级内存管理编程手册4:使用自动释放池块

自动释放池块提供了一种机制,你可以借助这种机制放弃对象的所有权,但又不会造成对象的立即销毁(例如当你从一个方法中返回对象时)。一般情况下,你不需要创建自己的自动释放池块,但也存在一些你不得不创建,或最好创建的情况。

关于自动释放池块

自动释放池块就是被@autoreleasepool标记的代码块。就像下面这样:

@autoreleasepool {
    // Code that creates autoreleased objects.
}

在自动释放池块的末尾,所有收到过autorelease消息的对象的release方法会被调用——在代码块中所有收到autorelease消息的对象都会收到release消息。
就像其他的代码块一样,自动释放池块可以嵌套:

@autoreleasepool {
    // . . .
    @autoreleasepool {
        // . . .
    }
    . . .
}

(这种代码并不常见,通常情况是位于某代码文件中自动释放池块内的代码会调用另一个代码文件中不同的自动释放池块内的代码。)当你在某个自动释放池块里给某个对象发送了autorelease消息,那么对应的release消息便会在这个自动释放池块的末尾发送给该对象。
Cocoa总是期望你的代码会放在一个自动释放池块内运行,否则本该自动释放的对象不会被释放,你的应用将会有内存泄漏。(如果你在一个自动释放池块的外边给对象发送了autorelease消息,Cocoa将会记录一条对应的错误信息。)AppKit和UIKit框架在每个事件循环迭代(例如鼠标或手指的轻点)过程中处理一次自动释放池块。所以通常你不需要亲手创建一个自动释放池块,或者说真正看到用来创建自动释放池块的代码。但以下三种情况则可能会需要你使用自己的自动释放池块:

  • 如果你所写的程序不是基于UI框架的时候,比如控制台工具。
  • 如果你写的循环中包含了大量临时对象的创建。
    你可能会在循环代码块内使用自动释放池块,从而在下次循环进行之前释放这些对象。在循环中使用自动释放池块会帮助改善应用程序的最高内存占用率。
  • 如果你使用了多个线程。
    你必须在线程开始运行之前创建自己的自动释放池块;否则,你的应用程序将会内存泄漏。(详细讨论参考下文自动释放池块与线程。)

使用局部自动释放池块降低最大内存占用率

一些程序会创建大量自动释放的临时对象。这些对象会在代码块结束之前增加程序的内存占用率。有时候,在当前时间循环迭代结束之前累积临时变量不会导致内存资源的过分消耗,但也有时候,巨大数量的临时对象会占据客观的内存资源,这时你可能会希望对象尽可能快地被销毁。在后者的情况下,你可能会需要创建自己的自动释放池块。在代码块的末尾,这些临时对象会被释放,通常这些对象的释放会降低程序的内存使用率。
下面的例子展示了在for循环中使用自动释放池块的例子:

NSArray *urls = <# An array of file URLs #>;
for (NSURL *url in urls) {
    @autoreleasepool {
        NSError *error;
        NSString *fileContents = [NSString stringWithContentsOfURL:url
                      encoding:NSUTF8StringEncoding error:&error];
        /* Process the string, creating and autoreleasing more objects. */
    }
}

for循环每次循环处理一个文件。所有的对象(例如fileContents)在自动释放池块内会收到一条autorelease消息,从而在自动释放池块的末尾被释放。
在自动释放池块之后,你应该意识到所有代码块内的对象都被“释放掉”了。不要给这些对象发送消息,或将它们返回给当前方法的调用者。如果你确实需要在自动释放池块之外使用一个临时对象,可以在代码块内给该对象发送一条retain消息,并在代码块之外再给它发送autorelease消息。示例如下:

– (id)findMatchingObject:(id)anObject {
    id match;
        while (match == nil) {
            @autoreleasepool {
            /* 进行一次搜索,从而产生大量临时对象。 */
            match = [self expensiveSearchForObject:anObject];
            if (match != nil) {
                [match retain]; /* 保持match对象。 */
            }
        }
    }
    return [match autorelease]; /* 返回match并使其自动释放 */
}

在自动释放池块内给match发送retain消息,并在自动释放池块外边给它发送autorelease消息。这扩展了match的生存空间,并使其可以在返回给findMatchingObject:方法的调用者后可以被正常使用。

自动释放池块与线程

<p id="jump1"></p>

Cocoa应用程序的每个线程都维持它们自己的自动释放池块栈。如果你正在写一个只使用了基础类库的程序,或者当你在分发一个新的线程的时候,你需要创建自己的自动释放池块。
如果你的程序或者线程是长时间活跃的,并且有可能会生成大量自动释放对象,那么你应该使用自动释放池块(就像AppKit和UIKit在主线程中所做的那样);否则,自动释放对象会累积,使内存占用率持续增加。如果你分发的线程里没有调用Cocoa的方法,那么你不需要使用自动释放池块。

注意: 如果你使用POSIX线程API来创建次要线程,而不是使用NSThread的话,除非Cocoa处在多线程模式,否则你不能使用Cocoa。Cocoa只有在分发了第一个NSThread对象后才会进入多线程模式。为了在POSIX次要线程中使用Cocoa,你的程序必须先分发至少一个NSThread线程对象——这个线程可以立即退出。你可以调用NSThread的类方法isMultiThreaded来判断Cocoa是不是处在多线程模式。

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

推荐阅读更多精彩内容