1
votes

I have a number of images I am filtering and when I do this in a serial queue that I create ,the memory is released after each block is complete. When I dispatch this work to the global GCD queue the memory doesnt release and gets out of control.

I wrapped the statements in an autorelease block but that doesnt seem to make a difference.

Is it due to the fact that the thread pool keeps references to the blocks somehow? After a while the memory gets released, but the app will crash before this with a large number of images.

Why is the memory being kept by the global queue and how could this be fixed so it releases after every block?

1
You should post your code. It's impossible to say from your description. The autorelease semantics of concurrent queues is, as you've seen, opaque and not immediate, so the general advice is to wrap the contents of blocks in @autoreleasepool, which you've done. I suspect to get more, you're going to have to give us more to work with. For instance, do you capture these images in the closure of a completion block that you submit to a queue? If so, that will extend the lifetime of the image until the completion block is finished. But yeah, it's hard to advise you without more info. - ipmcc
This turned out to be the GCD thread pool spawning loads of threads, each holding a huge filtered image in memory. I switched to a concurrent operation queue and tried different concurrency limits until the memory was manageable. - some_id
Also, FWIW, if GCD is spawning "loads of threads" where loads is > 3x number of cores, it probably means the blocks you're submitting to it are ending up blocked. A more performant approach would be to serialize the I/O on a serial queue, and do only the in-memory processing in parallel. One way to get help from GCD in this regard is to use dispatch_apply which will limit the number of concurrent operations. IME dispatch_apply will not create more than 2 * #cores threads. (Although that doesn't account for other, concurrent operations that may create threads.) - ipmcc

1 Answers

2
votes

You mentioned in your comments that GCD seems to be creating too many threads causing too many images to be in memory at once. If GCD is spawning "loads of threads" where loads is > 3x number of cores, it probably means the blocks you're submitting to it are ending up blocked (perhaps on I/O). A more performant approach would be to serialize the I/O on a serial queue, and do only the in-memory processing in parallel. One way to get help from GCD in this regard is to use dispatch_apply which will limit the number of concurrent operations. IME dispatch_apply will not create more than 2 * number-of-cores threads. (Although that doesn't account for other, concurrent operations that may create threads.)

Also, as you noted, NSOperationQueue allows you to specify a maximum number of concurrent tasks, which is another approach.