Using Instruments To Diagnose Retain-Cycle Bugs

Sat Mar 15 2014

So you've written your app and it all works great but it seems that as you use the app it become more and more sluggish or perhaps you get crashes that just don't make sense. You may be experiencing a retain-cycle bug. Because they are the most common version of the problem, this article revolves around retained View Controllers, but the technique can easily be modified to diagnose others.

Step-by-step guide

Let's start with your project (or workspace) loaded in Xcode:

  1. Launch Instruments from Xcode using ⌘-I
  2. Under Memory (or All), select the Allocations template
  3. Abort the initial trace run by hitting the Record button (🔴)
  4. Click on the information button on the Allocations instrument. You should see a popup that looks like this:
  5. Turn on Record reference counts
  6. Turn off Record all types and then click the Configure button. The popup will flip over to reveal this screen:
  7. What we want is to clearly see when our View Controller subclasses are being held on to for longer than they should be. Clear these Recorded Type rules by selecting them and hitting the remove button (minus). Using the add button (plus), add a new single rule that will track classes that end in ViewController. The result should look like this:
  8. Click Done. Here's what your popup configuration screen should look like now:
  9. Click the close button (X) and start a trace by clicking the Record button (🔴)
  10. Ensure that the Allocations instrument is selected (you may delete the VM instrument as we won't be using it) and choose Created & Still Living under Allocation Lifespan in the left lower detail view

What you should see

As your app presents and pushes View Controllers, you should see object retention (# Living) counts (or number of entries) rise. The graph should also rise to indicate an increase in retentions.

As it dismisses and pops them, you should see object retention counts (or entries) fall. The graph should also fall to indicate a decrease in retentions. The rule of thumb is that if you don't need a View Controller of a particular class at a specific point in your app, it shouldn't be taking up memory. As you return to your app's "home" screen, your graph should return to what it was when you started navigating around.

What you might see

If, however, you notice that as you navigate around your app, class counts continue to rise or you end up with a list of objects in the lower view that is more than what you would expect to still be "living", you may be facing a retain cycle bug.

Time to comb through your code and scream out to your peers on Twitter.

Although this article doesn't cover how to fix retain cycle bugs, a good starting place is this article here.

N.B. This guide assumes that you have followed standard Apple nomenclature for your objects so that at least all view controller descended classes have the suffix ViewController. It also assumes that you are not keeping strong references to view controllers for any particular reason (there are some good valid ones).

Return to list