GCD dispatch_async内存泄漏?

时间:2015-02-16 08:55:20

标签: memory-leaks grand-central-dispatch dispatch-async libdispatch

以下代码将占用~410MB的内存,不会再次释放。 (使用dispatch_sync代替dispatch_async的版本需要~8MB内存)
我预计会有高内存使用率的飙升,但它应该再次下降......泄漏在哪里?

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    for (int i = 0; i < 100000; i++) {
      dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
        NSLog(@"test");
      });
    }
    NSLog(@"Waiting.");
    [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:60]];
  }
  return 0;
}  

我试过了:

  • 在循环内部和内部添加@autoreleasepool
  • NSRunLoop run添加到循环

我尝试了几种组合,从未看到内存减少(即使在等待几分钟后)。 我知道GCD参考指南,其中包含以下声明:

  

虽然GCD调度队列有自己的自动释放池,但它们无法保证这些池何时耗尽。

此代码中是否存在内存泄漏?如果没有,有没有办法强制队列释放/排空已完成的块?

2 个答案:

答案 0 :(得分:1)

Objective-C阻塞它是一个C结构,我认为你创建100000个块对象来在后台线程中执行它们并等待系统运行它们。您的设备可以执行有限数量的线程,这意味着许多块将在OS启动之前等待。

如果你改变&#34; async&#34;在&#34; sync&#34;之后,将在完成并销毁前一个块之后创建下一个块对象。

UPD

关于GCD池。

GCD在GCD线程池上执行任务,线程由系统创建,并由系统管理。系统缓存线程以节省CPU时间,每个调度任务在自由线程上执行。

来自文档:

-

提交到调度队列的块在完全由系统管理的线程池上执行。不保证任务执行的线程。

-

如果您将任务作为同步任务运行,则在当前任务完成后存在空闲线程(来自GCD线程池)以执行下一个任务(因为主线程在任务执行时正在等待,并且不向该任务添加新任务队列),系统不分配新的NSThread(在我的Mac上我见过2个线程)。如果您将任务作为异步运行,那么系统可以分配许多NSThread(为了达到最大性能,在我的Mac上它接近67个线程),因为全局队列包含许多任务。

Here您可以阅读有关GCD线程池的最大数量。

我在Alocations分析器中看到,分配了许多NSThread并且没有被破坏。我认为这是系统池,必要时将被释放。

答案 1 :(得分:0)

始终将@autoreleasepool置于每个GCD通话中,您将没有任何问题。我有同样的问题,这是唯一的解决方法。

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    for (int i = 0; i < 100000; i++) {
      dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
        // everything INSIDE in an @autoreleasepool
        @autoreleasepool {
          NSLog(@"test");
        }
      });
    }
    NSLog(@"Waiting.");
    [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:60]];
  }
  return 0;
}