objective-c NSAutoreleasePool 自动释放池是如何工作的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/65427/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does the NSAutoreleasePool autorelease pool work?
提问by James Sumners
As I understand it, anything created with an alloc, new, or copyneeds to be manually released. For example:
据我了解,使用alloc、new或copy创建的任何内容都需要手动发布。例如:
int main(void) {
NSString *string;
string = [[NSString alloc] init];
/* use the string */
[string release];
}
My question, though, is wouldn't this be just as valid?:
不过,我的问题是,这不是同样有效吗?:
int main(void) {
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
NSString *string;
string = [[[NSString alloc] init] autorelease];
/* use the string */
[pool drain];
}
采纳答案by kperryua
Yes, your second code snippit is perfectly valid.
是的,您的第二个代码片段是完全有效的。
Every time -autorelease is sent to an object, it is added to the inner-most autorelease pool. When the pool is drained, it simply sends -release to all the objects in the pool.
每次 -autorelease 发送到一个对象时,它都会被添加到最内部的自动释放池中。当池被排空时,它只是将 -release 发送到池中的所有对象。
Autorelease pools are simply a convenience that allows you to defer sending -release until "later". That "later" can happen in several places, but the most common in Cocoa GUI apps is at the end of the current run loop cycle.
自动释放池只是一种便利,它允许您将发送 -release 推迟到“稍后”。“稍后”可能发生在多个地方,但在 Cocoa GUI 应用程序中最常见的是在当前运行循环周期结束时。
回答by mmalc
NSAutoreleasePool: drain vs. release
NSAutoreleasePool:排水与释放
Since the function of drainand releaseseem to be causing confusion, it may be worth clarifying here (although this is covered in the documentation...).
由于功能drain和release似乎是造成混乱,它可能是值得澄清这里(虽然这是覆盖在文档...)。
Strictly speaking, from the big picture perspective drainis notequivalent to release:
严格地说,从大局的角度drain是不等同于release:
In a reference-counted environment, draindoes perform the same operations as release, so the two are in that sense equivalent. To emphasise, this means you do notleak a pool if you use drainrather than release.
在引用计数环境中,drain确实执行与 相同的操作release,因此两者在这个意义上是等效的。强调一下,这意味着如果您使用而不是 ,则不会泄漏池。drainrelease
In a garbage-collected environment, releaseis a no-op. Thus it has no effect. drain, on the other hand, contains a hint to the collector that it should "collect if needed". Thus in a garbage-collected environment, using drainhelps the system balance collection sweeps.
在垃圾收集环境中,release是空操作。因此它没有任何作用。 drain,另一方面,包含对收集器的提示,它应该“在需要时收集”。因此,在垃圾收集环境中,使用drain有助于系统平衡收集清除。
回答by Neovibrant
As already pointed out, your second code snippet is correct.
正如已经指出的,您的第二个代码片段是正确的。
I would like to suggest a more succinct way of using the autorelease pool that works on all environments (ref counting, GC, ARC) and also avoids the drain/release confusion:
我想建议一种更简洁的使用自动释放池的方法,该池适用于所有环境(引用计数、GC、ARC)并避免排放/释放混淆:
int main(void) {
@autoreleasepool {
NSString *string;
string = [[[NSString alloc] init] autorelease];
/* use the string */
}
}
In the example above please note the @autoreleasepoolblock. This is documented here.
在上面的例子中,请注意@autoreleasepool块。这在此处记录。
回答by kperryua
No, you're wrong. The documentation states clearly that under non-GC, -drain is equivalent to -release, meaning the NSAutoreleasePool will notbe leaked.
不你错了。文档明确指出,在 non-GC 下,-drain 等效于 -release,这意味着 NSAutoreleasePool不会泄漏。
回答by Gagan_iOS
What I read from Apple: "At the end of the autorelease pool block, objects that received an autorelease message within the block are sent a release message—an object receives a release message for each time it was sent an autorelease message within the block."
我从 Apple 读到的内容:“在自动释放池块的末尾,在块内收到自动释放消息的对象会被发送一条释放消息——一个对象在块内每次收到自动释放消息时都会收到一条释放消息。 ”
回答by Hardik Mamtora
sending autorelease instead of release to an object extends the lifetime of that object at least until the pool itself is drained (it may be longer if the object is subsequently retained). An object can be put into the same pool several times, in which case it receives a release message for each time it was put into the pool.
向对象发送自动释放而不是释放会延长该对象的生命周期,至少直到池本身被耗尽(如果对象随后被保留,它可能会更长)。一个对象可以多次放入同一个池中,在这种情况下,每次将其放入池中时它都会收到一条释放消息。
回答by Loren Segal
Yes and no. You would end up releasing the string memory but "leaking" the NSAutoreleasePool object into memory by using drain instead of release if you ran this under a garbage collected (not memory managed) environment. This "leak" simply makes the instance of NSAutoreleasePool "unreachable" like any other object with no strong pointers under GC, and the object would be cleaned up the next time GC runs, which could very well be directly after the call to -drain:
是和否。如果您在垃圾收集(非内存管理)环境下运行它,您最终会释放字符串内存,但通过使用排放而不是释放将 NSAutoreleasePool 对象“泄漏”到内存中。这种“泄漏”只是使 NSAutoreleasePool 的实例像任何其他在 GC 下没有强指针的对象一样“无法访问”,并且该对象将在下次 GC 运行时被清理,这很可能在调用 之后直接进行-drain:
drain
In a garbage collected environment, triggers garbage collection if memory allocated since last collection is greater than the current threshold; otherwise behaves as release. ... In a garbage-collected environment, this method ultimately calls
objc_collect_if_needed.
流走
在垃圾回收环境中,如果自上次回收以来分配的内存大于当前阈值,则触发垃圾回收;否则表现为释放。... 在垃圾收集环境中,此方法最终会调用
objc_collect_if_needed.
Otherwise, it's similar to how -releasebehaves under non-GC, yes. As others have stated, -releaseis a no-op under GC, so the only way to make sure the pool functions properly under GC is through -drain, and -drainunder non-GC works exactly like -releaseunder non-GC, and arguably communicates its functionality more clearly as well.
否则,它类似于-release非 GC 下的行为,是的。正如其他人所指出的,-release是GC在无操作,所以唯一的办法,以确保池的正常运行下,GC是通过-drain,并-drain在非GC的工作原理完全一样-release在非GC,可以说是更清楚地传达其功能好。
I should point out that your statement "anything called with new, alloc or init" should not include "init" (but should include "copy"), because "init" doesn't allocate memory, it only sets up the object (constructor fashion). If you received an alloc'd object and your function only called init as such, you would not release it:
我应该指出你的声明“任何用 new、alloc 或 init 调用的东西”不应该包括“init”(但应该包括“copy”),因为“init”不分配内存,它只设置对象(构造函数时尚)。如果您收到一个 alloc'd 对象并且您的函数仅如此调用 init,您将不会释放它:
- (void)func:(NSObject*)allocd_but_not_init
{
[allocd_but_not_init init];
}
That does not consume any more memory than it you already started with (assuming init doesn't instantiate objects, but you're not responsible for those anyway).
这不会比您已经开始使用更多的内存(假设 init 不实例化对象,但无论如何您都不对这些负责)。

