5

在开发人员文档中,它说:

如果您的应用程序或线程是长期存在的并且可能会生成大量自动释放对象,您应该定期排空并创建自动释放池(就像 Application Kit 在主线程上所做的那样);否则,自动释放的对象会累积并且您的内存占用会增加。但是,如果您的分离线程不进行 Cocoa 调用,则不需要创建自动释放池。

我想知道最好的方法是什么。我有几种我认为可行的方法,但不知道哪个是“最好的”。我目前有一个方法可以启动线程并让它等待操作执行:

- (void)startThread
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    accessoryRunLoop = [NSRunLoop currentRunLoop];

    //Add a dummy port to avoid exiting the thread due to no ports being found
    [accessoryRunLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];

    while(accessoryThreadIsRunning)
    {
        //Keep the thread running until accessoryTheadIsRunning == NO
        [accessoryRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }

    [pool release];
}

我能想到的选择是:

1)在while(accessoryThreadIsRunning)中添加一个计数器,这样每50或100次它就会耗尽自动释放池并创建一个新的。

2)每次我在那个线程中执行一个方法(使用performSelector:onThread:),我可以创建一个自动释放池,然后在方法结束时释放它。

3)制作一个计时器,以便将池排空然后定期创建。

我认为选项 1 是最好的,但想知道是否有不同的方式我应该这样做。谢谢!

4

4 回答 4

4

我会从非常简单的开始,每次通过循环时创建/排出池。

如果它在性能分析期间显示为瓶颈,请修复它。

保持简单,直到分析表明需要复杂性。


我刚刚重新阅读了您的问题,并在我的回答中意识到了一些完全愚蠢的东西。如果您正在运行一个运行循环,它应该会自动为您管理一个自动释放池;它应该在循环顶部创建一个池,并在每次通过循环结束时将其排出。

如果您在运行循环之外还有其他事情,您只需要自己循环一个。是这样吗?

无论如何,是的,模式是:

 while(...) {
    ... create pool ...
    ... do stuff ...
    ... drain pool ...
 }
于 2010-09-27T19:38:59.763 回答
2

每次都把它排干。正如其他人所说,耗尽自动释放池很便宜。

此外,不排水可能会非常昂贵。如果您的自动释放池中有足够的东西导致分页,那么您会导致磁盘 I/O,而磁盘 I/O 的成本实际上是数千倍甚至数百万倍,然后运行一个链表调用 release on stuff。(在 iOS 等没有分页的系统上,大量等待自动释放的额外对象可能会导致内存不足警告,这可能会导致应用程序被迫退出,或者前台应用程序去释放一堆 Nib 视图或其他东西,然后它必须稍后重新创建......或者它可能只是强制您的应用程序退出)。

即使您没有使用“足够”的额外内存来导致内存不足警告或分页,您也将运行一个更大的陈旧的项目列表来耗尽。更多的内存访问将在您最新的自动释放项目和最旧的项目之间进行。最旧的自动释放项目现在在内存层次结构中更远的可能性更大,因此您的释放可能有缓存未命中与 L1 或 L2 缓存命中。因此,成本可能高出 100 倍。另外,您将释放的内存(并且可能在缓存中很热)很可能已被另一个对象重用。

因此,每 50 到 100 次执行一次自动释放甚至可能不会成为过早的优化。

每个循环执行一次发布,然后如果显示为瓶颈,则每 X 次执行一次,并确保它更快而不是更慢。

于 2010-09-28T18:41:15.453 回答
0

主线程的运行循环在每次通过时都会耗尽其池,因此在其他线程上也这样做是有意义的。如果您选择仅偶尔排空池,则可能会有大量自动释放的对象等待很长时间被释放。实际上,这取决于每次运行循环可以释放多少内存以及触发运行循环的频率。我总是喜欢在每次通过时都将其耗尽,因为它很容易并且可以帮助我将内存占用保持在尽可能低的水平。

于 2010-09-27T20:11:36.283 回答
0

传统的方法是,是的,每 50 次左右就保留一个计数器并排水,但正如 bbum 所说,从每个循环开始排水池,然后从那里开始。或者你可以-init得到你需要的对象,而不是创建任何自动释放的对象。(不要使用工厂方法)-release不过,请记住所有对象。

于 2010-09-28T02:20:28.843 回答