NSAutoreleasePool autorelease池如何工作?
据我所知,用alloc , new或copy创build的任何东西都需要手动发布。 例如:
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]; }
是的,你的第二个代码snippit是完全有效的。
每次-autorelease被发送到一个对象,它被添加到最内层的autorelease池。 当池被排空时,它只是将-release发送到池中的所有对象。
自动释放池只是一个方便,可以让你推迟发送“释放”,直到“以后”。 “稍后”可能发生在几个地方,但是在Cocoa GUI应用程序中最常见的是在当前运行循环周期结束时。
NSAutoreleasePool:排水与释放
由于drain
和release
的function似乎造成了混乱,在这里可能值得澄清(虽然这在文档中有所描述 )。
严格地说,从大局的angular度来看, drain
不等于release
:
在参考计数的环境中, drain
确实执行与drain
相同的操作,所以两者在这个意义上是等价的。 强调一下,这意味着如果你使用的是drain
而不是泄漏,那么你就不会泄漏水池。
在垃圾收集的环境中, release
是没有任何操作的。 因此它没有效果。 另一方面, drain
包含一个暗示,它应该“收集,如果需要”收集。 因此,在垃圾收集环境中,使用drain
帮助系统平衡收集扫掠。
正如已经指出的,你的第二个代码片段是正确的。
我想build议一个更简洁的方式来使用在所有环境(参考计数,气相色谱,弧)工作的自动释放池,也避免了排水/释放混淆:
int main(void) { @autoreleasepool { NSString *string; string = [[[NSString alloc] init] autorelease]; /* use the string */ } }
在上面的例子中,请注意@autoreleasepool块。 这是在这里logging 。
不你错了。 该文件明确指出,在non-GC下,-drain等同于-release,这意味着NSAutoreleasePool 不会被泄露。
我发现这个链接给出了何时以及如何使用NSAutoReleasePool: AutoReleasePool的最佳解释
是的,你的代码是完美的,如果你使用垃圾收集就足够了,只要设置string为零,当你完成它。 垃圾收集不利于您的应用程序的性能,所以我不会推荐使用它:P
我从Apple读取的内容是:“在自动释放池块结束时,在块内接收到自动释放消息的对象将被发送一个释放消息 – 对象每次在块内发送自动释放消息时都会收到释放消息。 “
发送autorelease而不是release到一个对象至less延长了这个对象的生命周期,直到这个pool本身被耗尽(如果这个对象被保留了,它可能会更长)。 一个对象可以放入同一个池中多次,在这种情况下,每次将对象放入池中时都会收到一条释放消息。
是和不是。 如果你在一个垃圾回收(而不是内存pipe理)的环境下运行它,你最终会释放string内存,但是通过使用drain而不是释放将NSAutoreleasePool对象“泄漏”到内存中。 这个“泄漏”只是使得NSAutoreleasePool的实例像GC之下没有强指针的任何其他对象一样,并且在下一次GC运行时清理对象,这可能直接在调用-drain
:
排水
在垃圾收集环境中,如果自上次收集以来分配的内存大于当前阈值,则触发垃圾收集; 否则就像发布一样。 …在垃圾收集环境中,这个方法最终会调用
objc_collect_if_needed
。
否则,就像非GC下的“ -release
行为”一样。 正如其他人所说的那样,“ -release
在GC下是不可操作的,所以确保GC在GC下正常工作的唯一方法是通过“ -drain
,非GC下的“ -drain
”与非GC下的“并可以更清楚地传达其function。
我应该指出你的语句“任何用new,alloc或init调用的”都不应该包含“init”(但应该包括“copy”),因为“init”不分配内存,只会设置对象(构造函数时尚)。 如果你收到一个alloc对象,而你的函数只是调用init,你就不会释放它:
- (void)func:(NSObject*)allocd_but_not_init { [allocd_but_not_init init]; }
这不会消耗比你已经开始的更多的内存(假设init没有实例化对象,但你不负责这些)。