96

据我了解,使用allocnewcopy创建的任何内容都需要手动发布。例如:

int main(void) {
    NSString *string;
    string = [[NSString alloc] init];
    /* use the string */
    [string release];
}

不过,我的问题是,这不是同样有效吗?:

int main(void) {
    NSAutoreleasePool *pool;
    pool = [[NSAutoreleasePool alloc] init];
    NSString *string;
    string = [[[NSString alloc] init] autorelease];
    /* use the string */
    [pool drain];
}
4

7 回答 7

69

是的,您的第二个代码片段是完全有效的。

每次将 -autorelease 发送到对象时,都会将其添加到最内层的自动释放池中。当池被耗尽时,它只是向池中的所有对象发送-release。

自动释放池只是一种方便,它允许您将发送 -release 推迟到“稍后”。“稍后”可能发生在几个地方,但在 Cocoa GUI 应用程序中最常见的是在当前运行循环周期的末尾。

于 2008-09-15T18:36:18.457 回答
37

NSAutoreleasePool:流失与释放

由于drainand的功能release似乎会引起混淆,因此可能值得在这里澄清(尽管这在文档中有所介绍......)。

严格来说,从大局来看drain并不等同于:release

在引用计数环境中,drain确实执行与 相同的操作release,因此两者在这个意义上是等效的。需要强调的是,这意味着如果您使用而不是.drainrelease

在垃圾收集环境中,release是无操作的。因此它没有效果。 drain另一方面,它包含对收集器的提示,即它应该“在需要时收集”。因此,在垃圾收集环境中,使用drain有助于系统平衡收集扫描。

于 2008-10-08T01:14:52.060 回答
17

正如已经指出的那样,您的第二个代码片段是正确的。

我想建议一种更简洁的方式来使用适用于所有环境(引用计数、GC、ARC)的自动释放池,并且还可以避免排放/释放混淆:

int main(void) {
  @autoreleasepool {
    NSString *string;
    string = [[[NSString alloc] init] autorelease];
    /* use the string */
  }
}

在上面的示例中,请注意@autoreleasepool块。这在此处记录。

于 2011-11-03T07:02:21.997 回答
7

不你错了。文档明确指出,在非 GC 下,-drain 等价于 -release,这意味着 NSAutoreleasePool不会被泄露。

于 2008-09-15T23:55:44.463 回答
0

我从 Apple 那里读到的内容:“在自动释放池块的末尾,在块内收到自动释放消息的对象会收到一条释放消息——对象每次在块内收到自动释放消息时都会收到一条释放消息。 "

https://developer.apple.com/library/mac/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html

于 2014-02-20T13:27:30.943 回答
0

向对象发送 autorelease 而不是 release 可以延长该对象的生命周期,至少直到池本身被耗尽(如果该对象随后被保留,则可能会更长)。一个对象可以多次放入同一个池中,在这种情况下,每次放入池中都会收到一条释放消息。

于 2014-06-27T13:07:08.080 回答
-2

是和不是。如果您在垃圾收集(不是内存管理)环境下运行它,您最终会释放字符串内存,但通过使用排水而不是释放将 NSAutoreleasePool 对象“泄漏”到内存中。这种“泄漏”只会使 NSAutoreleasePool 的实例“无法访问”,就像在 GC 下没有强指针的任何其他对象一样,并且该对象将在下次 GC 运行时被清理,这很可能是直接在调用之后-drain

流走

在垃圾收集环境中,如果自上次收集后分配的内存大于当前阈值,则触发垃圾收集;否则表现为释放。...在垃圾收集环境中,此方法最终调用objc_collect_if_needed.

否则,它类似于-release在非 GC 下的行为,是的。正如其他人所说,-release是 GC 下的无操作,因此确保池在 GC 下正常运行的唯一方法是 through -drain,并且-drain在非 GC 下的工作方式与非 GC-release下完全相同,并且可以更清楚地传达其功能好。

我应该指出,您的声明“用 new、alloc 或 init 调用的任何东西”都不应该包括“init”(但应该包括“copy”),因为“init”不分配内存,它只设置对象(构造函数时尚)。如果你收到一个分配的对象并且你的函数只调用了 init,你不会释放它:

- (void)func:(NSObject*)allocd_but_not_init
{
    [allocd_but_not_init init];
}

这不会消耗比您已经开始使用的内存更多的内存(假设 init 不实例化对象,但无论如何您都不对这些负责)。

于 2008-09-15T18:39:48.997 回答