1

In an app I'm working on for a client I create several concurrent dispatch queues at startup and then add long-running tasks to them using dispatch_async.

When the app gets ready to shut down, I set a global quit variable that causes the long-running tasks to exit their run loops, do final cleanup and exit.

I also set the (strong) variables that I use to keep track of my dispatch queues to nil. According to the docs, in ARC, dispatch queues are managed by ARC so I should not need to call dispatch_release on them once I am done with them.

Blocks running on the dispatch queues also hold owning references to their queues, but I've checked and all the blocks exit as expected shortly after I set the global quit variable.

I added __weak variables pointing to my dispatch queues, and several seconds after setting my quit flag and nil-ing out my strong references, I check the values in the weak variables. They should be nil because there should not be any more owning references to my queues. However, they don't go nil, and displaying them in the debugger shows a reference count of 1.

Has anybody else encountered this problem? I've gone over the code carefully and I don't see any block capturing problems. It's a client app that I'm doing as work for hire so I can't really post the code here unfortunately.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • That really should work. You're 100% certain there are no tasks left in the queues? – Rhythmic Fistman Oct 15 '15 at 02:05
  • 1
    Duncan: you should not looking at the reference count of anything. Do you have actual evidence of something leaking? – matt Oct 15 '15 at 02:26
  • 2
    Use Instruments -> Allocations. Make sure to check "Record Reference Counts". After you've run the app to the point where the queues should be released, drill down to one of the queues and look at its retain/release record. It takes a bit of time to grok the output, but you should be able to figure out where the unbalanced retain is coming from. – Avi Oct 15 '15 at 02:34
  • 1
    If this is happening at app termination, I don't understand why it matters whether you're "leaking" memory; everything is about to be reclaimed by the system anyways. Cocoa itself doesn't even do complete resource cleanup at termination. My guess would be, however, that your queues are still owned by libdispatch. – jscs Oct 15 '15 at 03:33
  • Yes it's true that in this specific case getting the dispatch queues to be released is not really an issue since they will be freed when the app terminates. I have other situations where I set up dispatch queues for a "run mode" and then shut them down when I stop run mode, so I wanted to learn how releasing dispatch queues worked. I was testing my cleanup code and decided to instrument the freeing of the dispatch queues. That was my test case, so that was what I described in this post. – Duncan C Oct 16 '15 at 00:19
  • @matt, I understand the limitations of reference counts. My evidence is that after all the jobs on a dispatch queue finish, and I nil out the only strong reference to it, the weak reference still points to my dispatch queue. (Since weak references should be nil'ed out when the object gets deallocated.) – Duncan C Oct 16 '15 at 00:22
  • 1
    But what I'm saying is, if you can't prove there's a leak, you should just "don't worry, be happy". – matt Oct 16 '15 at 00:30
  • I did prove that the dispatch queues were not being released when I removed the tasks they were running and released the last strong reference to them. – Duncan C Oct 16 '15 at 02:05

0 Answers0