DEV Community

loading...

A toddlers guide to memory leaks in Javascript

kepta profile image Kushan Joshi ใƒป5 min read

In this article I will take a very simplistic approach in understanding memory leaks and I will also attempt to diagnose them.

In todays world of abundant memory, we seldom worry about memory leakages. But I hate to tell you that we live in a real world and nothing comes for free.

Oh my fancy functional programming

Disclosure: I absolutely love functional programming.
Functional programming is cool and with the new ES6 syntax it becomes even cooler.

const arrayAddFirst = (a, b) => [a, ...b];
Enter fullscreen mode Exit fullscreen mode

This example above looks super good. Unless you bro-program with me and I blindly put it inside a heavy duty loop ๐Ÿ˜Ž.

result = newData.reduce((p,r) => arrayAddFirst(r, p), []); 
Enter fullscreen mode Exit fullscreen mode

Now I don't want you to judge me for the idiot code above. (virtual hug if you can guess what it does ๐Ÿ˜)


for(var i = 0; i < newData.length; i++) {
    for(var j = 0; j < i; i++) {
        // stuff here
    }
}
Enter fullscreen mode Exit fullscreen mode

The above code snippet is the old fashion equivalent of our example. Notice how easy it is to see it will run n * (n+1) / 2 times, where n is the length of newData.

The main problem in the example code is that the garbage collector has to kick in frequently. The fancy [a, ...b] array you create every time in the .reduce loop needs to be removed from memory or else it will eventually consume all of the memory.

This example tries to shed light on the important fact that memory is not your best friend. It works in your favour 99% of the time, but when it decides to stab you, it directly stabs you in the eye.

stab

Memory Leaks โ€ฆ.

Generally a javascript application can freeze in two ways:

Infinite loops: You might have accidently written a loop which never terminates.

var x = 0;
while(x < 5) {
   console.log(x); // Warning! do not try this at home 
}
Enter fullscreen mode Exit fullscreen mode

Running out of memory: We all know there is limited amount of memory in a computer and if we are not careful we might end up hogging all of the memory.

var x = [ [1] ];
for(var i = 1; i < 100000; i++) {
    x.push(arrayAddFirst(i, x[i-1])); // Warning! do not try this at home 
}
Enter fullscreen mode Exit fullscreen mode

Alright, but what about Memory Leaks??

Ofcourse, you can easily avoid these bad behaviours by being careful. But Memory leaks are one of those nasty devils which silently sit.

Let us define a computer which has infinite resources and let's call it Deep thought. We will refer to Deep thought in this article DT-42 and you will soon see how we will use DT-42 to figure out memory leaks.

Memory Leaks

A Memory leak in simple terms is forgotten data forever waiting to be used.
Let us see an example before we jump to a scientific definition.


function sayHi() {
    var allNames = [];
    var emoji = '๐Ÿ‘‹';
    return name => {
        allNames.push(name);
        return emoji + name;
        }
} 
Enter fullscreen mode Exit fullscreen mode

In the example, our program is becoming fatter everytime we call it. The garbage collector is not able to cleanup allNames because the function needs it to push data. It cannot figure out that allNames would never be read and hence it is futile to give it any space in memory.

The Wikipedia says:

memory leak is a type of resource leak that occurs when a computer program incorrectly manages memory allocations[1] in such a way that memory which is no longer needed is not released.

I find it much easier to understand the concept by thinking of it as a symptom. Your program is the patient whose love for memory keeps on increasing without bound.
love
Most of the time the computer (Garbage Collector) is good enough to spot most of data that you wouldn't be using anymore and cleans it up for you. But it is not perfect and we are far from having a garbage collector smarter than humans. (If we did have one, it would be writting the code and not us :P)

Give me some real life leakages

The problem with our real life is that we don't encounter such trivial memory leaks and most often the leakages are lurking behind a seemingly well behaving piece of code (Something as innocent looking as arrayAddFirst). Instead of throwing some real life leakages I would rather show you how to identify a memory leak.

Let us fire Chrome to help diagnose memory leaks.

  1. Open up an empty page.
  2. Open the dev panel (Command+Option+I or Control+Shift+I)
  3. Paste this example code in the console.
function sayHi() {
    var allNames = [];
    return name => {
            allNames.push(name);
            return '๐Ÿ‘‹ ' + name;
        }
}
var hello = sayHi();
hello('Gandhi');
Enter fullscreen mode Exit fullscreen mode

Alright, we have started leaking memory already, now let us open our memory profiler.

You should be able to find it as a memory tab in the dev tools.

image

For the scope of this article we will focus on Take Heap Snapshot. This functionality takes snapshot of the current memory usage of your program.

In my case it looks something like this:

image

Great, now we will run our innocent looking function a couple of times.

for(var i=0; i<1000000; i++) {
    hello('Gandhi');
}
Enter fullscreen mode Exit fullscreen mode

If you take another snapshot, you will see an increased memory usage.

image

In my case there is a complete difference of 10 megabytes. In a lot of real life cases a jump of several megabytes might be normal and you might want to take multiple snapshots over a span of time to rule out a leak.

You can easily compare two snapshots by clicking on the Summary dropdown and switching to Comparison.

image

If you compare your new snapshot with the one you took earlier and put #Delta to descending, you will find a huge number in the (string). This is where our memory is leaking. Click on it and you will see a lot of Gandhi's.

I really hope this article helped you in understanding memory. This is just one of the several approaches one can take to diagnose a leakage. Please check out the following links for a more advanced take on memory:

If you โค๏ธ this article, please share this article to spread the words.

Reach out to me on Twitter @kushan2020.

Discussion (10)

pic
Editor guide
Collapse
ardennl profile image
Arden de Raaij

This is gold and exactly what I needed! I'm writing a thing on analyzing performance issues and I almost forgot about memory leaks. Thank you :).

Collapse
kepta profile image
Kushan Joshi Author

Thanks for your kind words.

Collapse
blouzada profile image
Bruno Louzada

Nice post! Chrome dev tools are awesome

Collapse
5bentz profile image
5bentz • Edited

result = newData.reduce((p,r) => arrayAddFirst(r, p), []);
virtual hug if you can guess what it does

I'd say it reverses the order of the elements.

for(var j = 0; j < i; i++)
Notice how easy it is to see it will run n * (n+1) / 2 times

To me, it is easy to see it is an infinite loop :'D
With j++, it would run 0 + 1 +...+ n-1 times. Thus, n*(n-1)/2 times.

This article is a simple tutorial to memory leak & its analysis in a web browser =) I used Firefox 60 instead of Chrome without any hassle.

Thank you !

Collapse
arielgueta profile image
Ariel Gueta • Edited

But after you invoke the function, the GC needs to collect it, no?

var hello = sayHi();
hello('Gandhi'); <=== I'm done
If we were in the global scope you are right, but if I'm within a scoped module, it will released the memory as soon as the second line execute.

Collapse
kepta profile image
Kushan Joshi Author

As long as the โ€˜helloโ€™ variable is in reference ( global or modular ), it will keep leaking memory.
You can run the hello function yourself and see memory usage increasing.

Collapse
rapasoft profile image
Pavol Rajzak

Thank you for very informative article!

Are you aware of any differences between JS engines when it comes to garbage collection?

Collapse
kepta profile image
Kushan Joshi Author • Edited

I am not sure, but yes the GC varies wrt engines. I have read this great article on V8 medium.com/@_lrlna/garbage-collect...

Hope it helps you.

Collapse
rapasoft profile image
Pavol Rajzak

That's actually quite nice article, thanks!

Collapse
liveabhishek profile image
Masterchief

Your example is really awesome. When I ran the example I found that old references were in (array) section. I sorted by Size Delta. Maybe due to different version of chrome.