Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCD dispatch_async memory leak?

The following code will occupy ~410MB of memory and will not release it again. (The version using dispatch_sync instead of dispatch_async will require ~8MB memory)
I would expect a spike of high memory usage but it should go down again... Where is the leak?

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

I tried:

  • Adding @autoreleasepool around and inside the loop
  • Adding NSRunLoop run to the loop

I tried several combinations and never saw a decrease of memory (even after waiting minutes). I'm aware of the GCD reference guide which contains the following statement:

Although GCD dispatch queues have their own autorelease pools, they make no guarantees as to when those pools are drained.

Is there a memory leak in this code? If not, is there a way to enforce the queue to release/drain the finished blocks?

like image 552
Andreas Avatar asked Feb 16 '15 08:02

Andreas


People also ask

What is the main cause of memory leaks?

DEFINITION A memory leak is the gradual deterioration of system performance that occurs over time as the result of the fragmentation of a computer's RAM due to poorly designed or programmed applications that fail to free up memory segments when they are no longer needed.

Is memory leak serious?

Very dangerous. Memory leaks in the kernel level lead to serious system stability issues. Kernel memory is very limited compared to user land memory and should be handled cautiously. Memory is allocated but never freed.

What are the types of memory leaks?

There are two types of memory leaks: apparent and subtle. An apparent memory leak is a chunk of heap memory that's never referred from active memory, a subtle leak is memory that is still referred to but shouldn't be, i.e. a hash or dynamic array holds the references.


1 Answers

Objective-C block it is a C structure, I think you create 100000 the block objects to execute them in background threads and them wait while system can run them. Your device can execute limited count of threads, it means that many blocks will wait before OS start them.

If you change "async" to "sync", a next block object will be created after a previous block will be finished and destroyed.

UPD

About GCD pool.

GCD executes tasks on GCD thread pool, threads are created by the system, and managed by system. System caches threads to save CPU time, every dispatch task executes on free thread.

From documentation:

——

Blocks submitted to dispatch queues are executed on a pool of threads fully managed by the system. No guarantee is made as to the thread on which a task executes.

——

If you run the tasks as synchronized tasks, then exist the free thread (from GCD thread pool) to execute next task, after current task’s finished (because main thread is waiting while task execute, and does not add new tasks to the queue), and system does not allocate new NSThread (On my mac I’ve seen 2 threads). If you run the tasks as async, then the system can allocate many NSThreads (to achieve of maximum performance, on my mac it is near 67 threads), because the global queue contain many tasks.

Here you can read about max count of GCD thread pool.

I’ve seen in Alocations profiler that there are many NSThreads allocated and not destructed. I think it is system pool, that will be freed if necessary.

like image 186
Andrew Romanov Avatar answered Oct 15 '22 10:10

Andrew Romanov