在ARC(自动引用计数)的大多数情况下,我们根本不需要考虑Objective-C对象的内存管理。不允许再创建NSAutoreleasePools了,但是有一个新的语法:

@autoreleasepool {
    …
}

我的问题是,当我不应该手动释放/自动释放时,为什么我还需要这个?


编辑:简单总结一下我从所有的回答和评论中得到的东西:

新语法:

@autoreleasepool{…}是用于

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

更重要的是:

ARC uses autorelease as well as release. It needs an auto release pool in place to do so. ARC doesn't create the auto release pool for you. However: The main thread of every Cocoa app already has an autorelease pool in it. There are two occasions when you might want to make use of @autoreleasepool: When you are in a secondary thread and there is no auto release pool, you must make your own to prevent leaks, such as myRunLoop(…) { @autoreleasepool { … } return success; }. When you wish to create a more local pool, as @mattjgalloway has shown in his answer.


当前回答

@autoreleasepool不会自动释放任何东西。它创建了一个自动释放池,这样当到达块的末尾时,任何在块处于活动状态时被ARC自动释放的对象都将被发送释放消息。苹果的高级内存管理编程指南是这样解释的:

在自动释放池块的末尾,在块内接收到自动释放消息的对象将被发送一个释放消息——在块内每次发送一个自动释放消息的对象都会收到一个释放消息。

其他回答

@autoreleasepool不会自动释放任何东西。它创建了一个自动释放池,这样当到达块的末尾时,任何在块处于活动状态时被ARC自动释放的对象都将被发送释放消息。苹果的高级内存管理编程指南是这样解释的:

在自动释放池块的末尾,在块内接收到自动释放消息的对象将被发送一个释放消息——在块内每次发送一个自动释放消息的对象都会收到一个释放消息。

ARC并没有摆脱保留、释放和自动释放,它只是为你添加了所需的。所以仍然有保留的调用,仍然有释放的调用,仍然有自动释放的调用,仍然有自动释放池。

他们对新的Clang 3.0编译器和ARC所做的另一个改变是,他们用@autoreleasepool编译器指令取代了NSAutoReleasePool。NSAutoReleasePool一直是一个特殊的"对象"他们这样做是为了使用它的语法不会与对象混淆所以它通常更简单一点。

所以基本上,你需要@autoreleasepool,因为仍然有自动释放池需要担心。您只是不需要担心添加自动释放调用。

使用自动释放池的示例:

- (void)useALoadOfNumbers {
    for (int j = 0; j < 10000; ++j) {
        @autoreleasepool {
            for (int i = 0; i < 10000; ++i) {
                NSNumber *number = [NSNumber numberWithInt:(i+j)];
                NSLog(@"number = %p", number);
            }
        }
    }
}

当然,这是一个非常做作的例子,但是如果你在外部for循环中没有@autoreleasepool,那么你将在以后释放100000000个对象,而不是每次释放10000个对象。

更新: 也可以看到这个答案- https://stackoverflow.com/a/7950636/1068248 -为什么@autoreleasepool与ARC无关。

更新: 我研究了一下这里发生的事情,并把它写在了我的博客上。如果你看一下这里,你会清楚地看到ARC在做什么,以及新样式@autoreleasepool以及它如何引入一个作用域,被编译器用来推断哪些保留、释放和自动释放是必要的。

人们经常将ARC误解为某种垃圾收集或类似的东西。事实是,经过一段时间后,苹果公司的人(感谢llvm和clang项目)意识到Objective-C的内存管理(所有的保留和释放等)可以在编译时完全自动化。这是通过阅读代码,甚至在它运行之前!:)

为了这样做,只有一个条件:我们必须遵守规则,否则编译器将无法在编译时自动执行该过程。因此,为了确保我们永远不会违反规则,我们不允许明确地写释放、保留等。这些调用由编译器自动注入到代码中。因此在内部我们仍然拥有自动发行,保留,发行等内容。只是我们不需要再写了。

ARC的A在编译时是自动的,这比垃圾收集等运行时要好得多。

我们仍然有@autoreleasepool{…}因为它不违反任何规则,我们可以在任何需要的时候自由地创建/排泄我们的池:)。

引自https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html:

Autorelease Pool Blocks and Threads Each thread in a Cocoa application maintains its own stack of autorelease pool blocks. If you are writing a Foundation-only program or if you detach a thread, you need to create your own autorelease pool block. If your application or thread is long-lived and potentially generates a lot of autoreleased objects, you should use autorelease pool blocks (like AppKit and UIKit do on the main thread); otherwise, autoreleased objects accumulate and your memory footprint grows. If your detached thread does not make Cocoa calls, you do not need to use an autorelease pool block. Note: If you create secondary threads using the POSIX thread APIs instead of NSThread, you cannot use Cocoa unless Cocoa is in multithreading mode. Cocoa enters multithreading mode only after detaching its first NSThread object. To use Cocoa on secondary POSIX threads, your application must first detach at least one NSThread object, which can immediately exit. You can test whether Cocoa is in multithreading mode with the NSThread class method isMultiThreaded.

...

在自动引用计数(ARC)中,系统使用相同的方法 引用计数系统作为MRR,但它插入适当的内存 管理方法在编译时为您调用。你很坚强 鼓励在新项目中使用ARC。如果你使用ARC,就有 通常不需要理解底层实现 在本文档中描述,尽管在某些情况下可能是 有帮助的。有关ARC的更多信息,请参见过渡到ARC发行说明。

这是因为您仍然需要向编译器提供提示,说明何时自动释放对象超出作用域是安全的。