2

It's the first time I have to fix a memory problem from one of my iOS apps, so I'm not really sure how to track it, I've been reading some post from different blogs and I've found that my memory is constantly increasing:enter image description here

The problem is that I don't know how to track and fix the problems in my code, and I also don't know what should be the best "Growth" in memory. Thank you.

reojased
  • 709
  • 1
  • 7
  • 19
  • Try running the leaks instrument on your app. If what you have is a true memory leak it should find it. There are some designs that will cause your memory footprint to increase endlessly. For example, if you keep invoking segues to get to each new view controller without ever dismissing the old one you will increase your memory footprint forever as the stack of view controller grows and grows. – Duncan C Aug 06 '16 at 21:19

2 Answers2

2

First, I'd recommend watching WWDC 2013 Fixing Memory Problems and WWDC 2012 iOS App Performance: Memory videos. They are dated, yet still relevant, demonstrating of taking the above screen snapshot down to the next level in order to identify the underlying source of the memory issue.

That having been said, I have a couple of observations:

  • In my experience, nowadays, the problem is rarely "leaked memory" (i.e. memory that has been allocated, for which there are no more references, but you neglected to free it). It's rather hard to leak in Swift (and if you use the static analyzer on Objective-C code, the same it true there, too).

    The more common problem is "abandoned memory" resulting from strong reference cycles, repeating timers not getting invalidated, circular references between view controller scenes, etc. These won't be identified by the Leaks tool. Only by digging into the Allocations tool.

  • First, I often like to see what accounts for the bulk of the abandoned memory. So I double click on a top level call tree and it will show me where the abandoned memory was allocated:

    enter image description here

    Note, this doesn't tell me why this was abandoned, but by knowing where the bulk of the abandoned memory was allocated, it gives me some clues (in this example, I'm starting to suspect the SecondViewController).

  • I then drill into the generations results and start by looking for my classes in the allocations (you can also do this by manually selecting a relevant portion of the allocations graph, as discussed here). I then filter the results, searching for my classes here. Sure, this won't always be the most significant allocation, but in my experience this sort of abandoned memory almost always stems from some misuse of my classes:

    enter image description here

    Again, this is pointing me to that SecondViewController class.

    Note, when looking at generations, I generally ignore the first one or two generations because they may have false positives stemming from the app "warming up". I focus on the latter generations (and make sure that I only "mark" a generation when the app has been returned to some-steady, quiescent state.

  • For the sake of completion, it's worth pointing out that it's sometimes useful running Instruments with the "Record reference counts" feature on the unreleased allocation:

    enter image description here

    If you do that, you can sometimes drill into the list of retain and release calls and identify who still has the strong reference (focus on unpaired retain/release calls). In this case it's not very useful because there are just too many, but I mention in because sometimes this is useful to diagnose who still has the strong reference:

    enter image description here

  • If you're using Xcode 8, it has a brilliant object graph debugger that cuts through much of this, graphically representing the strong references to the object in question, for example:

    enter image description here

    From this, the problem jumps out at me, that I not only have the navigation controller maintaining a reference to this view controller, but a timer. This happens to be a repeating timer for which I neglected to invalidate. In this case, that's why this object is not getting deallocated.

In the absence of Xcode 8's object graph debugger, you're left to pouring through the retain and release references (and you can look at where each of those strong references were established and determine if they were properly released) or just looking through my code for things that might be retaining that particular view controller (strong reference cycles, repeating timers, and circular view controller references are the most common problems I see).

Community
  • 1
  • 1
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • I'm having one problem while tracking the memory issue, in none of the marks I get a view controller name such as you show in your screenshots, what does this means? I'm getting mostly things like class names and other kind of dependencies, just to tell a little bit more, I'm using map box, and apparently it appears continuously in the developer tools. – reojased Aug 07 '16 at 18:46
  • Look for any of your classes. If you don't see anything, think about caches, too. As that video describes, in addition to leaked memory (that cannot ever be accessed again) and abandoned memory (that won't ever be accessed again), there's also cached memory (that is unlikely to be used any time soon). This is why Allocations tool is useful, as you can identify _what_ is being allocated and not released and drive your analysis from there (and focus on those 20+mb generations). So, make sure all of your caches respond to memory pressure and then simulate memory warning and see what happens. – Rob Aug 07 '16 at 19:14
  • Ok, I'll check that, and one more thing, the first generation that is over 40mb is a problem? Or is it just the app "warming up"? @Rob – reojased Aug 08 '16 at 00:01
  • Apple advises that, when looking for leaks and abandoned memory, that you focus on memory consumption _after_ the app has been thoroughly exercised at least once because there can be allocations and caches that are set up by the OS that might be completely legitimate. See the "wasted memory" portion of [the graph here](http://stackoverflow.com/a/38532853/1271826). – Rob Aug 08 '16 at 00:10
  • 1
    Thanks man, the problem was mapBox and the map not being removed. – reojased Aug 11 '16 at 00:14
0

Minimizing your app's Memory Footprint

For the benefit of both stability and performance, it's important to understand and heed the differing amounts of memory that are available to your app across the various devices your app supports. Minimizing the memory usage of your app is the best way to ensure it runs at full speed and avoids crashing due to memory depletion in customer instantiations. Furthermore, using the Allocations Instrument to assess large memory allocations within your app can sometimes be a quick exercise that can yield surprising performance gains.

Apple Official Document

PinkeshGjr
  • 8,460
  • 5
  • 41
  • 56