I'm using Allocations to profile my app to see if it has any memory issues. Every time I click "Mark Generation" I get a new memory snapshot and I can see how much memory increases during two generations. However, the growth value always decreases for a few seconds until it stops, and I'm quite confused about this. Sometimes the initial growth can be more than 20MB, but finally drops to around a few hundred KB. Why is this and which value should I trust?
-
1I'm not following you. Perhaps you can post a brief [MCVE](https://stackoverflow.com/help/mcve) and a screen snapshot of the generations so that we can better understand the question. – Rob Jun 06 '22 at 17:37
-
But, as a general rule, when testing an app, we generally don't worry about the memory growth before and after the first iteration (quiescence before and after a cycle of the app), because that can include lots of caches and other things going on in the OS. We focus on the before and after of subsequent iterations, as that better reflects growth within our code as opposed to what's going on behind the scenes. – Rob Jun 06 '22 at 17:40
-
@Rob Hi, I just uploaded my screen shots and please take a look. You can notice the growth of Generation C & D. You can notice there is a big difference as time elapses. – P. Tsin Jun 07 '22 at 03:48
1 Answers
I would suggest that you simply do not focus on “generations” list, and its “growth” column, at all. It has a lot of noise in it (e.g. a ton of stuff that is going on the background) and does not capture some salient information.
Consider the following. I profiled an app that repeatedly allocates and deallocates a huge 70mb array. I marked generation A, then allocated the 70mb array, marked generation B, released the array, marked generation C, allocated the huge array again, marked generation D, released again, and then marked generation E:
The allocations graph accurately illustrates what I was doing in the app, but the “generations” list does not. It is telling me that generation D saw a growth of 26.95kb, even though actual memory usage went up by 70mb!
What is generally far more useful is the “Allocations” graph. Here I will select the interval from generation C to generation D:
When switched to the allocations list, and sorted in descending order of size, I now see my large array allocation. I even see a stack trace of where the allocation happened in Foo.init
. And that is indeed where the allocation is taking place:
class Foo {
let values = Array(0 ..< 10_000_000)
}
class ViewController: NSViewController {
var foo: Foo?
@IBAction func didTapCreate(_ sender: Any) {
foo = Foo()
}
@IBAction func didTapRelease(_ sender: Any) {
foo = nil
}
}
I confess that most allocations problems are not this easy to find. I manifested an easily discovered issue by doing a single huge allocation. Because reverse engineering the allocations can be so difficult, unless I am dealing with unsafe pointers and manually allocated buffers, my first line of investigation is generally Xcode’s “debug memory graph” (see https://stackoverflow.com/a/30993476/1271826).
I might also advise watching WWDC 2021 video Detect and diagnose memory issues and see the various other links on that page. It describes a lot of very advanced techniques.
Regarding the changing of previous generations’ “growth” values, it safe to say that to the extent that “growth” has value at all, one can safely assume that the final value is more reliable. Real-time instruments logging (as opposed to “deferred” logging) frequently updates previous graphs and values as Instruments catches up with all of the logged events.

- 415,655
- 72
- 787
- 1,044
-
Thanks for your suggestions. I've noticed that the "growth" column value does not match the difference between two generation mark points in the graph, and this makes me quite confusing. Okay, I'll focus more on the graph instead. – P. Tsin Jun 08 '22 at 02:50
-
Also, "memory graph" is really a good tool, but unfortunately my device is running iOS 13.2.2 and it seems there's a bug on older OS versions(https://stackoverflow.com/questions/53666493/how-to-fix-no-reply-dictionary-received-from-leakagent-request-error-in-xcode), so I have to debug on Allocations. – P. Tsin Jun 08 '22 at 05:40
-
Assuming, of course, that you couldn’t just use a simulator with a more contemporary iOS version… – Rob Jun 08 '22 at 07:16
-
As I start to look at the "Allocations List" & "Statistics", I find that the "Created & Persistent" memory cannot match the difference between two generation mark points in the graph either, in my app. In a simple demo, the calculation is correct, but my app is a complicated one and this difference is huge. For a selected interval in the graph, it creases from 120MB to 140MB, but in the list it says there are 60MB persistent. – P. Tsin Jun 08 '22 at 07:27
-
Well, I’d suggest that you post a new question with a [MCVE](https://stackoverflow.com/help/mcve). It’s hard to help you without a reproducible example. It shouldn’t be as complicated as your actual app, but rather the bare minimum amount of code necessary to manifest the problem. – Rob Jun 08 '22 at 07:35