Fortunately, there are better ways of approaching this problem. In particular, Chrome’s Allocation Timeline is a great tool for isolating and investigating memory leaks in your app.
The Allocation Timeline will show you stack traces that can help you identify which part of your code is responsible for allocating particular objects. To use this feature, you need to enable a DevTools setting that is disabled by default. Open your DevTools settings, find the Performance section, and check “Record heap allocation stack traces.”
With that out of the way, let’s run through our example. We’ll work with the following page:
Here’s a version you can play with in your browser. When the “Allocate” button is clicked, the script on the page repeatedly allocates 1–3 MB of memory with which to store a string. References to these strings accumulate in the
strings array until the “Release” button is clicked.
Open Chrome’s Task Manager and let the script run for several seconds. You should see the page consume an increasing amount of memory.
Now pretend we don’t already know the cause of this elevated memory usage. The Allocation Timeline can help us find the source of our leak (i.e., what’s using the memory that can’t be freed). To use it, select “Record allocation timeline,” located under the DevTools’ Memory tab.
Click the “Start” button to run the profiler, then click the “Allocate” button on our example page. You’ll see blue bars appear on the timeline.
Blue bars represent allocated memory that hasn’t been freed. If you click the “Release” button, the blue bars become gray bars.
Gray bars represent previously allocated memory that has been freed. Stop the profiler using the circle in the upper left.
Blue bars that remain on the allocation timeline when you stop a recording indicate potential memory leaks. To explore this case, re-run the profiler, click the “Allocate” button, then stop the profiler before clicking the “Release” button. You should be left with a timeline full of blue bars. Narrow your focus to a single blue bar by zooming in.
This limits the “Constructor” list to objects allocated in the highlighted span. In this case, we see that 2.8 MB worth of strings were allocated in this time span. (To learn more about the difference between shallow size and retained size, see the Memory Terminology section of the DevTools docs.)
Expanding the entry for the
(string) constructor reveals that a single 2.8 MB string was allocated here. We can see the string itself, and by opening the “Allocation stack” tab, we can see a stack trace telling us exactly where this string was created.
In many cases, this stack trace can point you to the place in your code that needs fixing more quickly than if you were to attempt finding that spot without it.
Keep in mind that you can export allocation timeline snapshots by clicking the “Save” link in the sidebar. This is helpful if you find yourself profiling an especially busy or leaky app, in particular one that’s prone to crashing. This can slow down the DevTools to the point that they’re unusable, or in the case of a crash, cause you to lose your timeline altogether.
Instead of letting the app continue to run while you frantically inspect the timeline, save a snapshot, close the tab in which the app is running, take a deep breath, open a new tab, open the DevTools, then load your saved snapshot.
Memory leaks happen from time to time. The next time you encounter one, remember that the Allocation Timeline is your friend.
Plug: LogRocket, a DVR for web apps
LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.