Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to "find mystery retains" ...?

Recently I was repairing someone's code. There was a big class that would not dealloc. You'd have to hit it with 5 or 6 releases to get it to dealloc.

I carefully looked through the big class and eventually found the various things that needed to be released.

This got me thinking: there just has to be some really easy way to "find" all the retains on an object .. am I right?

So, is there a simple way to "find all the retains" on an object? Is there a button in XCode or Instruments that everyone else knows about?

What do you do when you can't find a mystery retain like that?

So in the iOS universe, if anyone knows the "Show where all the retains came from on this object" button -- thanks!

P.S. Note that there is no leak, and this question is totally unrelated to leaks. The object simply "perfectly correctly" wouldn't release.


Later ..

Truly astounding solution by Fabio:

Fabio has provided an astounding solution to this problem. In nine words, here it is:

-(id)retain     {     NSLog(@"%@", [NSThread callStackSymbols]);     return ([super retain]);     } 

That is amazingly useful in many situations and leads to many other useful things. You've probably saved me two man-weeks of work per annum forever, Fabio. Thanks!

BTW if you're just getting to grips with this and struggling with the output, I saw that typically there will be many chunks featuring "UINib instantiateWithOwner:". It looks like those will come first, the significant chunks will follow.

like image 480
Fattie Avatar asked Apr 07 '11 20:04

Fattie


1 Answers

Instruments can show you the call stack for every malloc, release, and retain for any Obj-C object in your app with no code changes required. It works when you're using ARC, which is not the case for the solution from fabio.

It's really useful for finding those mystery retains - e.g. when an object just won't dealloc when it should.

Here's how:

  • CMD + I (Product / Profile)
  • When Instruments pops up choose 'Allocations' (NOT Leaks)
  • Your app should run.
  • Do whatever causes your mystery retains to happen.
  • Select the 'Allocation' instrument on the left-hand panel.
  • Press CMD + 1 or select the circle with the wave in it on the right. In the panel on the lower right, tick the 'Record reference counts' option. This is important, or only mallocs and frees will be recorded.
  • In the search box on the top-right of the list, type the name of your class (e.g. BCMyObject).
  • This filters the list of 'Statistics' to show how many instances of your class are currently live. The #Persistent column shows how many instances are live.
  • Click the row, and then the little arrow -> next to the class name. You'll see the breadcrumbs shows 'Statistics > Allocation Summary > BCMyobject'
  • This shows you all the instances of said class (and which ones are live).
  • Select an instance, and click the arrow again (this time by address)
  • Now you'll see 'Statistics > Allocation Summary > BCMyObject > History: 0xADDRESS' in the breadcrumps.
  • This'll list every time the object is malloc'd retained or released.
  • Now in the left panel where the 'Record Reference Counts' option was, press the icon that looks like a bar with boxes connected to it or press CMD + 3.
  • Select one of the rows and you'll see the complete call stack that led to the call.

Easy! (ish)

like image 52
Ben Clayton Avatar answered Sep 21 '22 21:09

Ben Clayton