CoderBear's Blog
Memory leaks in JavaScript
June 22, 2015

What is a memory leak?
The memory lifecycle in any programming language can be summed up as follows; 1. Allocate memory 2. Read/Write to it 3. Deallocate memory when not required anymore. Failing to release a block of memory that is no longer required for a program to function correctly. This is not to be confused with optimization, where the code is improved upon to consume less memory.


What happens when I have one?
Blocks of memory that should be freed - but are not - pile up and block resources. In time, the page starts getting noticeably slow and depending on the system configuration, the browser/server may hang, perhaps eventually crash.


Why can’t the JavaScript Garbage Collector or Browser fix it?
It can, and it does, but only partly. Leaks come from various sources - add ons, certain edge cases in the browser's GC implementation. But the major source of such leaks often resides in our code. In that case, the GC becomes pretty helpless, and the only way to deal with it is to write better code.

In a nutshell, the idea of this series of posts is to identify certain code crevices which lead to memory leaks, go through the workings of the components involved, and finally see the corresponding fixes to avoid such crevices. The first step is to understand the JavaScript Garbage Collector (JS GC).


How does the JS GC work?
Once an element is not referred to by any other element, or can't be reached via a path, it is deemed no longer required, and is marked for garbage collection. With this basic principle in mind, follow this example to try and get a feel of how things actually work.


  <!-- HTML code -->
  <html>
  <head>
  <meta name="description" content="Garbage Colelction in JS 1">
    <meta charset="utf-8">
    <title>JS Bin</title>
  </head>
  <body>
    <div id="id">Some Data</div>
  </body>
  </html>
        

  // JS code

  function testFunction(title) {
    this.title = title;
    this.elem = document.getElementById('id');
  }

  var firstObject = new testFunction('My Menu');

  console.log('1 - Title is ' + firstObject.title);
  console.log('2 - Elem is ' + firstObject.elem);

  document.body.innerHTML = '';

  console.log('3 - Title remains ' + firstObject.title);
  console.log('4 - Note that Elem too remains ' + firstObject.elem);

  firstObject.elem.innerHTML = 'New Data';
  console.log('5 - You can play around with Elem ' + firstObject.elem);
  console.log('6 - Elem is not attached to the DOM anymore though, its parent is - ' + firstObject.elem.parent)

  secondObject = new testFunction('His menu');

  console.log('7 - New title ' + secondObject.title);
  console.log('8 - New Elem is ' + secondObject.elem);
        

We’re creating an object firstObject, with two properties. The second property, elem, points to an object in the DOM. Logs number 1 and 2 are pretty straightforward. Next, we clear up the DOM completely, thus removing the element elem points to. While log 3 is normal, note how log number 4 still points to the previously existing element i.e, <div id="id"></div>. Since elem is still being referred to, it won’t be garbage collected.

Also note how you can still manipulate menu.elem but it won’t reflect in the DOM. Thats because the body has been wiped clean by the statement document.body.innerHTML = '';. The elem now will infact incorporate the change to its innerHTML, but it won't be visible as it is now a stand alone element, an 'orphaned' element so to say. This is confirmed by log number 6. For curiosity's sake, you can comment out the line document.body.innerHTML = ''; and watch the html then respond to changes made by firstObject.elem.innerHTML = 'New Data';.


Next, we create a new object, and log number 7 is as expected. elem will now be looked up in the DOM, searching for an element with id id and finding none, will be assigned null. The previous elem will now be available for garbage collection.

Lastly, assume a scenario where the second object is not created and the memory remains blocked for the lifespan of the page. Combine this with a much more complicated, real world object with lots of properties and multiple such instances. The significance of this is now much more apparent.


JS Bin on jsbin.com


In the next post, I shall describe more such cases, following which we'll take a look at how to avoid/handle such unintended traps.

Feel free to get back to me with any doubts or clarifications. I shall try my best to answer each one of them personally.

Update, 30 June 2015 : I've edited the intro to add some more context.



Receive my blogs in your email. Subscribe.

Only Javascript. No Spam. Promise.