NSAutoreleasePool自动释放池是如何工作的?

发布于 2024-07-06 07:03:08 字数 520 浏览 8 评论 0原文

据我了解,任何使用 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];
}

As I understand it, anything created with an alloc, new, or copy needs to be manually released. For example:

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];
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

生来就爱笑 2024-07-13 07:03:08

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

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

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

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 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.

灼痛 2024-07-13 07:03:08

NSAutoreleasePool:耗尽与释放

由于 drainrelease 的功能似乎引起混乱,因此可能值得在这里澄清(尽管这在 文档...)。

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

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

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

NSAutoreleasePool: drain vs. release

Since the function of drain and release seem to be causing confusion, it may be worth clarifying here (although this is covered in the documentation...).

Strictly speaking, from the big picture perspective drain is not equivalent to release:

In a reference-counted environment, drain does perform the same operations as release, so the two are in that sense equivalent. To emphasise, this means you do not leak a pool if you use drain rather than release.

In a garbage-collected environment, release is 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 drain helps the system balance collection sweeps.

橘亓 2024-07-13 07:03:08

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

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

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

在上面的示例中,请注意 @autoreleasepool阻止。 此处记录了此内容。

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:

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

In the example above please note the @autoreleasepool block. This is documented here.

時窥 2024-07-13 07:03:08

不你错了。 文档明确指出,在非 GC 下,-drain 相当于 -release,意味着 NSAutoreleasePool 不会被泄漏。

No, you're wrong. The documentation states clearly that under non-GC, -drain is equivalent to -release, meaning the NSAutoreleasePool will not be leaked.

始终不够爱げ你 2024-07-13 07:03:08

我从苹果公司读到的内容:
“在自动释放池块的末尾,块内接收到自动释放消息的对象将被发送一条释放消息——每次在块内发送自动释放消息时,对象都会收到一条释放消息。”

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

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."

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

挖鼻大婶 2024-07-13 07:03:08

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

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.

记忆之渊 2024-07-13 07:03:08

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

排水

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

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

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

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

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

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:

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.

Otherwise, it's similar to how -release behaves under non-GC, yes. As others have stated, -release is a no-op under GC, so the only way to make sure the pool functions properly under GC is through -drain, and -drain under non-GC works exactly like -release under non-GC, and arguably communicates its functionality more clearly as well.

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:

- (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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文