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:
NSRunLoop run
to the loopI 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?
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With