Detect and fix memory leaks to boost your application performance – and what to do to avoid them in the future.
- Memory leaks are created when we keep unintentional references to objects and thus prevent Garbage Collection from clearing the objects
- Using chrome developer tools it is very easy to detect a memory leak.
- Once you detected a leak, you can fix it
- You can fix a memory leak by making sure you have no unintentional reference to objects you do not need anymore.
What is a Memory Leak?
In “old” languages like C and C++ the developer had to allocate and release the memory explicitly. If the program would have lost a reference to an object, that would have resulted in a leak since the developer would not have been able to clear the object.
The symptoms that hint on a leak is an application that gradually declines in performance over time. It would usually happen in a SPA that starts smoothly and after a few user’s actions starts to run slower and slower. In Node.js it will be seen as a server that responds slower and slower to api calls.
In figure 1 we see a memory profile of an application running. The memory (blue area above the timeline) keeps rising. The yellow arrow marks a GC point which does not reduce the memory to the baseline level (the level at the beginning of the recording).
This might hint on a leak – but this is not necessarily a leak. It might be that our application received data from the server or that it created DOM elements for showing some data. You will have to understand the scenario in which you have profiled in order to make sure the leak hint is indeed hinting on a leak and not a valid memory allocation.
The Memory tab in the dev tools is the tool that can give you detailed allocation information. With this information, you can pinpoint your heaviest allocating functions or find the exact objects or arrays that keep reference to objects you might have wanted to be garbage collected.
The “classic” way of finding leaks was using the Heap snapshot in the Memory tab. This snapshot gives you the current state of memory at the time the snapshot was taken. When using Heap snapshot, you’d usually:
- Get to a starting point in the application
- Take a snapshot of the baseline state
- Enact some use case in the application
- Take another snapshot
- Revert the use case and return to the starting point
- Take another snapshot
- Compare the first snapshot to the last one.
So for instance, you start your app, click a button that opens a modal window and close the modal window. You’d expect that the comparison of the first and last snapshot will yield minor differences. That means that in our case, opening and closing the modal removed most of the objects that were allocated in the process of opening and interacting with the modal.
In figure 2 we see 3 snapshots were taken (blue rectangle). We compare snapshot 3 to snapshot 1 (using the dropdowns in the green rectangle). The red rectangle shows us a major difference between snapshot 3 and 1. 3000 DOM elements were added and were not cleared.
Might it be that our modal window created elements that are still referenced from the code?
Then again, it might not be the case, because you’d might expect the modal to have some side effects – like getting data from the server and populating a data grid. It might be the user filled a form and the data saved prompted the creation of new objects. In any event, you will see the objects that were created and decide if it is valid they are still there or if you expect them to be garbage collected.
An easier way to find memory leaks and their origin is to use the Allocation instrumentation on timeline. In this tool, you see the live allocation of the objects as they are created. You also see the live garbage collection of the objects.
Figure 3 shows the recording on a timeline. Figure 3a shows the recording of 3 allocations that were not cleared. We can see that the bars are still blue (hence, they are still in memory). We can also see the allocation in each blue bar is at about 51.2kb.
Figure 3b shows a focus on one of the allocations. We can see what was allocated (a 1000 DOM elements in this case) and we can find out the retainers of the DOM elements. The fact we have “Detached” before the DOM elements is a big hint for a DOM leak. This means we have DOM elements that were removed, but are still referenced from our code.
Figure 3c shows the same scenario only now the elements were garbage collected and appear as gray bars. Notice the allocation level is 1kb which means even the blue bar is something very small and negligible and we have nothing to fear in regards to a leak in this case.
The third option of finding a source for a leak is the allocation sampling. This tool gives you the data about how much memory was allocated by certain functions.
Figure 4 shows the result of allocation sampling. Figure 4a shows the bottom up view. We can see that addElement was the function that allocated the most memory in the app. Figure 4b shows a chart of the functions in the app by their allocation size.
How To Fix A Memory Leak?
There are other types of memory leaks. Another common type is forgotten timers or listeners. For instance, you’ve setup a setInterval at a certain point in the application and then closed that part of the application. The setInterval, being a global function, keeps on running until you run clearInterval. If you forgot to use clearInterval or clearTimeout it will result in the interval and all of its context are still referenced and not garbage collected.
You’d might also add listeners to a DOM element, and then forget to remove them when they are no longer needed. For instance, a modal window that sets a listener on some external element. The modal is closed, but the external element still has that listener in place. This will cause the same effect as with forgotten timers, as the listeners are kept on the element itself.
Leaks happen when your app still references objects that are no longer needed. In the frontend it might be DOM elements or any other object. In the backend it might be pieces of data received from an external source. We also saw that timers and event listeners can be the source of a leak.
Once in a week I publish a FREE newsletter for developers and programmers who are interested in taking their skills to an expert level.
And I invite you to sign up right now. Just a few of my optimization techniques can make a big difference to the performance of your applications.
Sign Up for our FREE newsletter and get our best articles delivered to you by e-mail
What you will learn:
- An easy, effective way to TEST your code and find places to make improvements
Enter your name and email to access your FREE membership
*** We take your privacy very seriously. We hate spam as much as you do, so rest assured that your contact details will never be shared with a third party.
Easy ways to test and improve Node.js performance
Here’s how to measure Node.js code efficiency and significantly boost Node’s performance. Simple tips that will improve your Nodejs code CPU and memory consumption.