How to Debug Memory Leaks When Leaks Instrument Does Not Show Them

How to debug memory leaks when Leaks instrument does not show them?

In Xcode 8, you can click on the "Debug Memory Graph" button, debugmemorygraphbutton in the debug toolbar (shown at the bottom of the screen):

debug memory graph

See Apple’s Diagnosing and Resolving Bugs in Your Running App: Visualize and Diagnose Increasing Memory Usage.

Just identify the object in the left panel that you think should have been deallocated, and it will show you the object graph (shown in the main canvas, above). This is very useful in quickly identifying where the strong references were established on the object in question. From here, you can start your research, diagnosing why those strong references were not resolved (e.g. if the object in question has a strong reference from something else that should have been deallocated, look at that object's graph, too, and you may find the issue (e.g. strong reference cycles, repeating timers, etc.).

Notice, that in the right panel, I'm seeing the call tree. I got that by turning on the "malloc stack" logging option in the scheme settings:

malloc stack

Anyway, having done that, one can then click on the arrow next to the relevant method call shown in the stack trace in the right panel of the first screen snapshot above, and you can see where that strong reference was originally established:

code


The traditional Instruments technique (especially useful if using older versions of Xcode) is described below, in my original answer.


I would suggest using Instruments' "Allocations" tool with the "Record Reference Counts" feature:

record reference counts

You can then run the app in Instruments and then search for your class that you know is leaking and drill in by clicking on the arrow:

Sample Image

You can then drill into the details and look at the stack trace using the "Extended Details" panel on the right:

extended details

In that "Extended Details" panel, focus on your code in black rather than the system calls in gray. Anyway, from the "Extended Details" panel, you can then drill into your source code, right in Instruments::

your code

For more information and demonstrations in using Instruments to track down memory problems, please refer to:

  • WWDC 2021 video Detect and diagnose memory issues
  • WWDC 2019 video Getting Started with Instruments
  • WWDC 2018 video iOS Memory Deep Dive
  • WWDC 2013 video Fixing Memory Issues
  • WWDC 2012 video iOS App Performance: Memory

iOS Memory leaks , memory graph debugger shows no leaks but in parallel Xcode-Instruments-leaks shows leaks

In the 2013 video, Fixing Memory Issues), Apple made a distinction between “leaks”, “abandoned memory”, and “cached memory”, discussed below. For more contemporary discussions, see WWDC 2021 video Detect and diagnose memory issues, WWDC 2019 video Getting Started with Instruments, and WWDC 2018 video iOS Memory Deep Dive.

  • Leaked memory is that which can’t be accessed again, memory for which there are no references left, i.e., memory that has been malloc’ed but never free’d.

  • Abandoned memory consists of memory that which does have references, but which won’t be accessed again.

  • Cached memory is that which might not be used again, held in memory for fast retrieval in case the app needs it again.

The “debug memory graph” excels at finding and visualizing issues arising from strong reference cycles. The “Leaks” instrument will not identify these issues. As strong reference cycles and the like, are more prevalent in Swift code, often the “Debug Memory Graph” is a more fruitful first line of defense.

When debugging memory issues, we worry less about the memory usage between the first and second iterations as we cycle through the app, but rather focus on subsequent iterations.

Anyway, the “Leaks” tool and the “debug memory graph” were focusing on different problems and would generate different results. Leaks does not find strong reference cycles. At the same time, the “debug memory graph” feature has gotten much better at finding traditional leaks.

FWIW, in Swift, strong reference cycles are far more common than traditional malloc-but-no-free leaks. Your Swift code is unlikely to have traditional leaks unless you start delving into manual allocation of buffers, unmanaged Core Foundation API, etc.

And if you are seeing memory growth in your app, before you worry about leaks, make sure it’s not the third memory issue identified in the aforementioned video, namely, cached memory, that which might not be used again, but will be automatically reclaimed when the device runs low on memory.


As an aside, occasionally there are reported leaks buried in the OS or frameworks. If (a) you do not see your target referenced in the stack traces; or (b) the leaks are inconsequental, then I might suggest not worrying too much about them at all. In your case, we’re talking about 384 bytes, not something I’d worry too much about.

XCode/Instruments not showing memory leaks

It appears as if there is no detectable leak. Look at this line:

brain = [[CalculatorBrain alloc] init];

As long as brain points to an object, that object won't be considered a "memory leak". If at some point you do this,

brain = nil;

Then the leak will register. Deallocating the container object will also achieve this, but are you sure it's being deallocated? (It won't be deallocated when your program exits, for example.)

The problem: Leak detectors cannot detect all memory leaks -- this is a mathematically proven fact. Most detectors only detect unreachable objects, and many leak detectors are especially susceptible to false negatives -- in C it is hard to tell the difference at runtime between a pointer and an integer.

Edit: It sounds like your application only ever creates one instance of the controller, which only creates one instance of CalculatorBrain. If you think about what a memory leak really is, you can define it as unused memory that your program does not release back to the operating system.

  • While the program is running, CalculatorBrain is always in use and therefore it is not a leak.
  • When the program exits, the operating system automatically reclaims all memory used by your process, therefore there cannot be any memory leaks after a program exits.

If you want to create a leak to see what it looks like, you could create a new CalculatorBrain multiple times while your program is running, but forget to release the unused versions. In this scenario, as your program runs, more and more instances of CalculatorBrain would accumulate. On iOS and other embedded systems, this will generally crash your program. On a modern 64 bit computer it will gradually fill up the available swap space until you run out of swap, address space, or some other resource -- causing the program to crash or making the system very unresponsive.

Standard practice is to not care about deallocating objects which are supposed to exist for the entire program's run.

Unable to locate memory leak using Xcode Instruments

I'm rather suspicious of the way you're managing the copied node; you may be releasing it prematurely, and only the retain cycle was preventing you from discovering this mistake. However, let's concentrate on breaking the retain cycle.

What you want to do is make everything coming into the action method weak, so that there is no strong capture by the action method. Then in the action method you want to immediately retain those weak references so they don't vanish out from under you. That's called the "weak-strong dance". Like this:

    copiedNode.run(copiedNodeAction) { [weak self, weak copiedNode] in
if let `self` = self, let copiedNode = copiedNode {
// do stuff here
// be sure to log so you know we arrived here at all, as we might not
}
}

Can't detect C leaks in xcode 9 instruments

There is no problem with your code. It creates a memory leak as you expected. The problem(actually its good) is with the Xcode.

Xcode optimises your code to remove all the memory leaks. Thats why instruments not showing any memory leaks.

To see your memory leaks, disable the optimisations in the Xcode.

Sample Image

Select None [-O0] to disable all the optimisations.


You use intstruments to profile the final production code. So, don't change the Release settings. You may forget to change it back and your program will not be optimised.

Instead edit the scheme of Profile from Release to Debug. Doing this you can always get optimised code for the Release.

1). Click on executable icon
Sample Image

2). Click on Edit Scheme.
Sample Image

3). Change the Build Configuration to Debug.
Sample Image

Now, whenever you profile your code, you will get all the errors as your code is not optimised.

To profile your release code, change it back to Release in the Build Configuration.

Using instruments to find memory leaks

The problem shown in your screenshot is Instruments can't find your app's debug symbols. Instruments is showing memory addresses instead of function names. You are not going to be able to find the source of your memory leaks in Instruments without function names, even if you invert the call tree and hide system libraries.

Make sure your project is generating debug symbols. Check that the Generate Debug Symbols build setting is set to Yes. If your project is generating debug symbols, Instruments may be unable to find the dSYM file that contains the debug symbols. In Instruments choose Instrument > Call Tree > Locate dSYM. The dSYM is usually in the same directory as the release version's application bundle. The following article has additional information:

Instruments: Locating dSYM Files

Using instruments tool to locate leaks

Finding a leak is not that simple. You need to wear the detective cap, take out your magnifying glass from your coat and start find the trail. i.e.

For every leaked object there is a responsible library. If it is a UIKit, Foundation or anything low-level, you won't be able to pin point the location of code that is causing the leak since these libraries are in the form of binaries.

If the responsible library is the one you are writing then you can go to the code by clicking the right method in the stack trace panel on the right. One hint is that the methods listed in the stack trace panel become highlighted if there is a corresponding code available.

But, since it is not that straight forward, often your own piece of code causes some internal library to leak which is hard to debug. You need to go through some tutorials and practice material before you start. Something certainly not answerable on stackoverflow.

Instruments Leaks - Not showing my source code

Remove any non-ascii characters from both your your startup disk

and hostname (see the Sharing panel in System Preferences)
and restart.

Ta da!



Related Topics



Leave a reply



Submit