Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS: How to identify the leak from Xcode instruments?

I have utilised the profiler to look out for memory leaks and came across this issue:

enter image description here

I switched to call Tree.

So I could click on it to find out more about it:

enter image description here

But it doesn't really give me any clue. How should I know what was causing the leak?

enter image description here

UPDATE:

  • the call tree with system libraries shown is updated above.
  • information about the objects leaked:

enter image description here

  • some description of what you do in the app to reproduce this leak:

Our app is syncing with our REST-API upon start (foreground) of the app. This works always on my iOS 7/iPhone 4S. But another developer has iOS7/iPhone 5 and runs seldomly into the problem that it doesn't sync. After 10 days of observing and putting NSLogs everywhere, we found this last night:

Dec 15 03:18:58  appname[4801] <Warning>: A gateway to the host server is working via WWAN.
Dec 15 03:18:58  appname[4801] <Warning>: Syncing...
Dec 15 03:18:58  appname[4801] <Warning>: Eventname to be fired: f11-reachability
Dec 15 03:18:58  appname[4801] <Warning>: Sync event IOS_REACHABILITY reached.
Dec 15 03:18:58  appname[4801] <Warning>: Sync: IOS_SYNC_WITH_SERVER is true
Dec 15 03:18:58  appname[4801] <Warning>: Animating indicator...
Dec 15 03:18:58  appname[4801] <Warning>: Getting last timestamp: 1387003344.407783 then calling syncWithServerWithDate
Dec 15 03:19:27  com.apple.launchd[1] <Notice>: (UIKitApplication:com.apple.mobilecal[0x45fb]) Exited: Killed: 9
Dec 15 03:19:27  com.apple.launchd[1] <Notice>: (com.apple.afcd) Idle-exit job was jettisoned. Will bypass throttle interval for next on-demand launch.
Dec 15 03:19:27  com.apple.launchd[1] <Error>: (com.apple.afcd) assertion failed: 11B554a: launchd + 35697 [3C91C465-EFA6-32C7-A677-DD0B5FDEE0DC]: 0x9
Dec 15 03:19:27  com.apple.launchd[1] <Notice>: (com.apple.absd) Idle-exit job was jettisoned. Will bypass throttle interval for next on-demand launch.

A third attempt to sync (pressing home button and coming back to foreground) gave us this, which indicated a low-memory:

Dec 15 03:25:18 C1 appname[4801] <Warning>: Getting last timestamp: 1387003344.407783 then calling syncWithServerWithDate
Dec 15 03:25:29 C1 profiled[6244] <Notice>: (Note ) profiled: Service stopping.
Dec 15 03:25:40 C1 crash_mover[6248] <Notice>: (Warn ) <crash_mover.m mv_recursive:98> Moving './LowMemory-2013-12-14-160222.plist' -> '/var/mobile/Library/Logs/CrashReporter/LowMemory-2013-12-14-160222.plist'

So I thought I give the profiler a go and see if I find anything.

In order to reproduce it, I have started the app, went to Home screen, then pressed the Simulate a Low Memory and then clicked on the app to come back to the foreground. This is where I get the red spike.

  • what Xcode version you're running.

Xcode 5.02. iOS 7.04 on iPhone 4S (OK), iPhone 5 (rare edge case)

I hope this helps. Thank you

like image 627
Houman Avatar asked Dec 15 '13 13:12

Houman


1 Answers

As menacing as the red spike in Leaks appears, the total memory leaked is 1.06kb, which is extremely unlikely to be the source of (nor even related to) your problem.

In terms of your app resulting in the jettisoning of other apps, that, itself, is not a problem and I'd be less concerned about that (though, to be a good citizen, you really should try to minimize that). The more immediate functional issue is why your app is failing to sync and whether this really is a result of a memory warning within the app itself (or more accurately, a failure of your app to sufficiently free resources in response to a memory warning, resulting in subsequent memory allocations to fail).

In my mind, the first question is whether you're really getting memory warnings in your app. Generally, I'd see something like the following in the console if the app really had a memory warning:

Dec 15 11:12:26 Robs-iPad myapp[2224] : Received memory warning.

But I don't see the above in your console dumps, so it makes me wonder whether you're really receiving memory warnings.

I might suggest inserting explicit logging in your app delegate:

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
    NSLog(@"%s", __FUNCTION__);

    // free whatever caches or other temporary resources you can here
}

or put in special handling in the view controller:

- (void)didReceiveMemoryWarning
{
    NSLog(@"%s", __FUNCTION__);

    [super didReceiveMemoryWarning];

    // do whatever you want to free resources here

    [[[UIAlertView alloc] initWithTitle:nil
                                message:@"didReceiveMemoryWarning"
                               delegate:nil
                      cancelButtonTitle:@"OK"
                      otherButtonTitles:nil] show];
}

That would result in seeing the following in my console:

Dec 15 11:12:26 Robs-iPad myapp[2224] : -[AppDelegate applicationDidReceiveMemoryWarning:]
Dec 15 11:12:26 Robs-iPad myapp[2224] : -[ViewController didReceiveMemoryWarning]

But the key goal is to confirm whether you really are receiving memory warnings and whether that truly correlates with your app's failure to sync.

But let's assume for a second that the problem is, indeed, a result of a memory warning. That then leads to two questions: First, what are you doing to mitigate the memory warnings in the first place (e.g. using @autoreleasepool to mitigate high-water mark, not holding large resource in memory at the same time if not absolutely necessary, using imageWithContentsOfFile rather than imageNamed)? Second, what are you doing in response to the memory warnings (e.g., are you purging caches, etc.)?

So, if you do confirm that the memory warning is truly the source of the problem (and do that first), then it might be interesting to look at your allocations graph during a synchronization process (and confirm the peak number of live bytes, as well as the final number of live bytes). Looking at the allocations graph in your question, it doesn't look too bad (i.e. no wild swings), but then, again, you haven't shared with us the number of "live bytes", so it's hard to say.

But I definitely wouldn't be worrying about this leak of 1kb when you simulate a memory warning. That's more of an annoyance than any serious symptom that you need to worry about. Keep an eye out for leaks, but focus on (a) large leaks; and (b) those in your code, not in the frameworks.


My original answer, below, was in response to the original question which was merely "what is this leak shown by instruments that doesn't seem to correspond to my code". I'll keep it here for reference:


This might suggest that the leak is not in your code, but rather in the system frameworks (which you've hidden).

You might want to share:

  • the call tree with system libraries shown;

  • information about the objects leaked (so, not just the "call tree", but the "leaks" list, too);

  • some description of what you do in the app to reproduce this leak;

  • which iOS versions you see this problem manifest itself, and which versions you do not (the frameworks are not without leaks themselves, but it varies by iOS target); and

  • what Xcode version you're running.

Frankly, you might end up disregarding this issue given (a) the negligible size of the leak; (b) the lack of indication that the problem rests in your code; and (c) the fact that iOS frameworks do have leaks outside of your control. But if you're concerned, share some of the above information and we might be able to offer further observations.

like image 76
Rob Avatar answered Oct 21 '22 04:10

Rob