Javascript Memory Management

As the web evolved, the static pages turned into Ajax driven single-page applications. These SPA’s enabled web application to have better performance and re-usable code. Memory management is quite important when writing these applications (Eg: Angular JS, Backbone, Ember) as they never get refreshed. This means that memory leaks can become apparent quite quickly, specially when using them on mobile devices which have limited memory

How is the memory managed in Javascript ?

Like many other advanced programming languages, javascript also has a Garbage Collectors. There are 2 main algorithms which are used by the browsers:

  1. Reference Counting
  2. Mark Sweep Collection

Reference Counting

When an object is created, Javascript automatically allocates an appropriate amount of memory for that object. It has a reference count of 1. When ever the object is assigned to a new variable then the reference count is incremented and when ever the reference is assigned a new object or is out of scope the reference count is decremented by 1. The object’s having reference count zero are the ones which are not having any references and are considered non reachable. When the garbage collection starts the memory is reclaimed from objects with zero reference count.

This algorithm fails when there are islands of isolation or cyclic dependencies. That is Object A referring Object B and Object B referring Object A. When both of them are out of scope the reference count of both is 1, hence causing memory leak.

Mark and Sweep Collection

This is a more effective algorithm that is used by most if the modern browsers. In this method, when a variable comes into context, such as a variable is declared inside a function it is marked as in context. When it goes out of context it is marked as out of context. This is the Mark step.

Later the garbage collector identifies all the variables which are not in context or not referenced by variables in context. These variables are considered as ready for deletion as they can’t be reached by any in-context variables. When the collector does the memory sweep, it destroys all the objects which are marked ready for deletion.

This is one of the main reasons why we should avoid global variables because global variables are always in context and they are never destroyed by the garbage collector and hence globals are only cleaned up then you refresh the page.

Important facts about Memory Leak and Javascript Performance

De-Referencing

Mank developers think that they can force a GC and reclaim memory by using the delete keyword. This is not the case. Let us see what happens when we use the delete keyword in the below example:

var object = { x: 1, y: 2 }; delete o.x;//true o.x; //undefined

In this case this code, the delete key word changes the structure of the object which in-turn changes the hidden class and makes it a generic slow object. This makes the access to the other properties of the object slow. The better solution would be setting the value to null. Setting the object reference to null does not mean “null” the object. It sets the object reference to null.

o.x = null;

Functions and Garbage Collection

Consider the following code example:

function foo() { var bar = new SomeHugeObject(); bar.someMethod(); }

When foo returns, the object bar no longer remains in the context and hence is eligible for garbage collection. But if we have the following case:

function foo() { var bar = new SomeHugeObject(); bar.someMethod(); return bar; } //Calling function var a = foo();

In this case, we now have a reference to the object which is in the context. Hence this object is not eligible for garbage collection till the reference a points to some other object or a goes out of scope.

Memory leak due to closure

A closure is created when there is a function and it returns an inner function which uses variables from the outer function. For example:

function outer () { var a = "Long String"; function inner (newString) { a = a + newString; } return inner; } var fun1 = outer();

In this case the variable ‘a’ will remain in memory even after the execution of outer is complete because of a closure created. This will remain in memory till fun1 is not assigned some other object or it is in scope.


Originally published at mayank.co on December 9, 2014.