9

我是 Objective-c 的新手,我知道基本的内存管理规则,比如 when to retain release autorelease. 但我不知道什么时候应该将我的代码包装到自动释放池中,为什么?

4

4 回答 4

22

与其他性能优化一样,如果您注意到高内存使用和分析(例如使用 Instruments)导致您将额外的自动释放池作为解决方案,您通常应该只在代码中添加额外的自动释放池。

也就是说,您可以将创建大量临时对象的代码包装在自动释放池中的紧密循环中。默认的自动释放池在运行循环周期结束时被耗尽。因此,如果您在代码中 for 循环的每次迭代中创建大量临时对象,则默认自动释放池将在整个循环运行之后才会耗尽,这意味着您创建的所有临时对象可以加起来高临时内存使用率(有时称为“高水位线”)。您可以将循环的每个迭代包装在 an 中@autoreleasepool,以使在该循环迭代中创建的不需要的、自动释放的临时对象更快地释放。

于 2012-05-13T16:39:31.873 回答
12

要扩展以前的答案:

自动释放池用于release自动向添加到其中的对象发送消息。

在 iOS 或 Cocoa 程序中,自动释放池会在主线程上自动创建,并在运行循环结束时耗尽。

也就是说,在另一个线程上使用自动释放对象时,自动释放池是强制性的。

因此,如果您将线程分离到某个方法,则将线程代码包装在自动释放池中。否则,线程中创建的自动释放对象只会泄漏。

自动释放池的另一个用途是优化将使用大量内存的部分代码,因此它们在运行循环结束之前被释放。

但它只涉及自动释放的对象。

例如:

- ( void )test
{
    NSMutableArray * a = [ [ NSMutableArray alloc ] init ];

    [ a release ];
}

这里不需要自动释放池,因为您没有自动释放的对象。
a变量将被立即释放,因为它已被显式分配并释放。

现在这个:

- ( void )test
{
    NSMutableArray * a = [ NSMutableArray arrayWithCapacity ];
}

在这里,您使用的是便利构造函数,这意味着您没有该对象的所有权。
这也意味着该对象已添加到当前的自动释放池中(如果有的话)。

所以当这个自动释放池被耗尽时它会被释放,所以它可能需要一些周期......

如果您正在编写的代码部分使用大量内存,您可以使用另一个自动释放池,以便在您的方法返回时释放您的自动释放对象:

- ( void )test
{
    @autoreleasepool
    {
        NSMutableArray * a = [ NSMutableArray arrayWithCapacity ];
    }
}
于 2012-05-13T17:03:37.193 回答
1

所有自动释放的对象在技术上都放在一个自动释放池中。通常在您的 main 函数中创建一个默认值。至于在非默认自动释放池中包装对象,这通常是作为一种优化来完成的。

通常不需要使用显式的自动释放池,因为默认的自动释放池会在应用程序的运行循环中自动耗尽。但是,如果您的应用程序在从事件处理程序返回之前创建了许多自动释放的对象,则它可能会为这些对象使用大量内存。因此,如果您将代码包装在显式自动释放池中,则自动释放的对象将被放置在那里,而不是默认池。这允许您定期清空此池以防止自动释放的对象累积。

于 2012-05-13T16:52:14.000 回答
0

但是,在三种情况下您可能会使用自己的自动释放池块:

  1. 如果您正在编写不基于 UI 框架的程序,例如命令行工具。

  2. 如果您编写一个创建许多临时对象的循环。您可以在循环内使用自动释放池块在下一次迭代之前处理这些对象。在循环中使用自动释放池块有助于减少应用程序的最大内存占用。

  3. 如果你产生一个辅助线程。

于 2013-09-04T23:45:32.417 回答