Search
Follow
Recent Comments

Entries in instruments (2)

Tuesday
Mar082011

Using heapshots to find abandoned memory

There are a number of techniques for finding memory leaks in iOS applications including using the Build and Analyze option in Xcode and the Allocations instrument. However neither of these approaches will find memory that has been abandoned.

Abandoned Memory

To clarify what I mean by abandoned memory I mean memory that has been allocated and is still referenced somewhere in the application but that is no longer really required. Since the memory is still referenced it is not a leak so will not show up using the leak instrument. It may have been caused by some old, now long forgotten, code that is no longer required. The trick is to identify that you have some abandoned memory. A refactoring of the responsible code can then clean up the problem.

To illustrate the problem consider the following scenario. An action is triggered each time a button is tapped which allocates a number of objects. These objects are cached by the view controller because at the time the original code was developed there was an idea to reuse the objects elsewhere in the controller. However maybe the reuse never happened or the reason for the optimisation has long since disappeared but the cache remains.

A simplistic implementation of the method that is triggered by the button being pressed might look something like this:

- (void)doSomething {
 
  for (int i = 0; i < 100; i++) {
 
    NSString *textData = [[NSString alloc] initWithFormat:@"text data item %d",i];
    [self.cache addObject:textData];
    [textData release];
  }
}

Each time the button is tapped we are allocating 100 NSString objects and retaining a reference in a cache object. The cache object is just an array with a property definition as follows:

@property (nonatomic,retain) NSMutableArray *cache;

 

Of course, this is a trivial example just to illustrate the technique for finding abandoned memory. In practise the code may be much more complicated making it less obvious that it can be refactored.

Using the Heapshot Instrument

To run an app with the heapshot tool use Xcode and from the Run menu select Run With Performance Tool > Allocations. (Alternatively you can run Instruments directly and use it to attach to the target application running in the simulator or on a device). By default, the allocations tool shows the Statistics view, we need to switch to the Heapshots view by selecting it from the menu.

You should now see a button in the left hand pane under Heapshot Analysis labeled “Mark Heap”. Each time you use the Mark heap button a snapshot of the application heap is taken.

The useful thing about this though is that each time you take a heapshot Instruments will show you how much the heap has grown since the last snapshot and how many of the newly created objects are still live. To see why that is useful we can take a look at my dumb example app. The basic technique for discovering abandoned memory is as follows:

  1. Start from a known state in the application
  2. Generate a baseline heapshot
  3. Perform a series of actions to exercise the app functionality under test
  4. Return to the known application state
  5. Generate a new heapshot
  6. Repeat several times from step 3

My app consists of a single button which when tapped invokes the doSomething method I showed earlier (I did say it was a dumb app). So starting from the home screen of the app I will first generate the baseline heapshot with the Mark Heap button. Then to exercise the app I will tap the UI button a few times each time using the Mark Heap button to generate a heapshot:

What is immediately obvious is that each time I tap the button in the app I am adding 100 (sometimes 101) objects to the heap occupying a little over 3KB. Drilling down one level into the heapshots you can see that the newly created objects are mostly CFString objects:

If I drill down a further level and click on one of the objects the stack trace in the right hand pane of Instruments makes it obvious that these strings are being allocated in our doSomething method:

What the heapshot cannot tell you directly is if these objects should be living on once we have completed the function we are testing. However there is something suspicious about objects that get added to the heap each time we perform a function. Where heapshot is invaluable is in highlighting areas of your app that are worth further investigation. In this case pointing us to the code that is caching objects would be enough of a hint to review how the cache is being used and either fix the implementation or remove it completely if it is no longer required.

Monday
Jul052010

Tracking background memory usage of iOS 4 apps

A quick follow up on yesterdays post about adding multitasking support to an iOS 4 app. I mentioned the recommendation from Apple to reduce your memory usage when entering background mode without mentioning how you determine what you are currently using.

VM Tracker

A new memory analysis instrument called VM Tracker was added to the Xcode Instruments tool with iPhone OS 3.1 to allow you to examine the virtual memory space of a process. Note that you need to be running on Snow Leopard to use VM Tracker. Unfortunately the documentation for VM Tracker does not yet seem to have made it into the Instruments User Guide so you have to look at the iPhone SDK Release Notes for iPhone OS 3.1 for details. The most interesting piece is on the Summary view:

Summary view - This view shows the total amount of memory by region type. Individual regions are grouped by region type and show their contribution to the type’s overall usage statistics. This view is primarily useful as an overview of how a process’ memory is being used, and it is recommended that special attention is paid to the “dirty” sizes, as these represent memory that must be paged to disk under memory pressure on Mac OS X and are completely unreclaimable memory on iPhone OS.

The “dirty” memory is what counts when an application is moved into the background and suspended. So this is the memory that needs to be reduced to a minimum if we want to increase the chances of surviving in the background.

To use the VM Tracker instrument run the application on a test device using the Run with Performance Tool > Allocations option from the Xcode Run menu. This will launch the application and attach Instruments to the running process with the Allocations and VM Tracker instruments.

The VM Tracker tool needs to suspend the app whilst taking a snapshot of its virtual memory so by default Apple has not enabled it to automatically snapshot the app. Since we are not in this case worried about impacting the application performance we can enable the Snapshot Automatically option with the default interval of 3 seconds. Alternatively you can manually click the Snapshot Now button after the app has entered the background and been suspended to record its memory usage.

With instruments running exercise the app to get a typical memory footprint and then use the home button to send it into the background. You should see two flags appear on the Instruments timeline. The first flag indicates that your app is entering the background (applicationDidEnterBackground is called at this point) and the second indicates the app has been suspended (click on the flag for details).

Once you have a snapshot of your app in the suspended state you can examine the VM Summary view to see the DIrty Size in MB (in the final column of the first row labeled *Dirty*). In the example below the app is using 5.90 MB.

I am still not sure what represents “High” memory utilisation so if you try this leave a comment for comparison but my feeling is that anything below 5-10 MB is “low” (time will tell if this is a good guess). What is probably more important is to go back and check your apps memory usage from time to time to ensure that it has not dramatically increased. The final test of whether an app is using too much memory is if users start to report that the app is being terminated by the system whilst in the background. Hopefully Apple will provide some feedback in the future on how they are seeing typical apps behave.