Skip to main content

Avoiding Memory Leaks:
A peek in Browsers' Closure's Optimization

In this post, I want to cover a Closure optimization meant to help us preventing memory leaks. This optimization is implemented by the three major browsers: Chrome, Firefox and IE. Closure is a popular subject and you can find very good articles out there. Although the post won't cover Closures internals, I will briefly cover the basics in order to keep the reading fluent.

Basics

To put it shortly; any time we access a method in JS, a special context object is created. This object contains the variables to be searched in the scope chain search process.

  
var x = 10;
(function parentFunc () {
    console.log(x);
}()); //* Result: 10

The code above will print 10 because when the parentFunc method is executed, a special context object containing its parent's variables is created and is pointed by parentFunc method scope. When the interpreter starts searching for 'x' value it searches inside the parentFunc scope. If it can not find it, its parent scope gets evaluated. In this case, the parent scope is the global scope (window in browsers implementation, global in nodeJS).

Inner functions actually capture the entire parent scope and add it to the chain:

 
var x = 10;
var funcResult = (function parentFunc () {
    var x = 20;
    var y = 30;
    var sonFunc = function () {
        console.log(x + y);
    }
    return sonFunc;
})();
funcResult();//* Result 50

When sonFunc is returned, the parentFunc scope with x (20) and y (30) variables is captured and added to the search chain. When funcResult is called, and console.log(x + y) is encountered, the interpreter searches the variables 'x' and 'y' inside sonFunc. Once it concludes it can't find them, it searches them inside its parent scope, (as I've explained, parentFunc was added to the chain).

Note that if we comment-out var x = 20 code line, the result will be 40. Because the interpreter won't find the 'x' variable inside parentFunc, it will search in parentFunc's parent scope where 'x' value is 10.

Classic Memory Leak

JS's function-callback nature leads a lot of developers to make use of Closures, but the first thing you should note when using Closures is that they can lead to memory leaks. In order to prevent leaks while using callbacks/closures you must be always aware of what your code is keeping in memory and make sure it vanishes as soon as possible. For example, let's examine the following code snippet:

 
var listFunc= [];

setInterval(function hello(){
var funcResult = (function parentFunc () {
    var x = 20;
    var y = 30;
    var sonFunc = function () {
        var text = "X value is: " + x + " and Y value is: " + y;
        console.log(text);
    }
    return sonFunc;
})();
listFunc.push(funcResult);  

},100);

In the above sample for each interval iteration parameters, 'x' and 'y' are re-created and kept in memory. Newbies might think that sonFunc keeps in memory only the string value but in practice 'x' and 'y' values are kept in memory as well, making this a classic memory leak.

Browsers' Closure's Optimization - Avoid Severe Memory Leaks

In the previous sample, the inner function had a reference to both external values, as result 'x' and 'y' were kept in memory by the internal closure function. In the next example the inner function holds a reference to x variable only:

 



var listFunc= [];

setInterval(function hello(){
var funcResult = (function parentFunc () {
    var x = 20;
    var y = 30;
    var sonFunc = function () {
        var text = "X value is: " + x;
        console.log(text);
    }
    return sonFunc;
})();
listFunc.push(funcResult);  

},100);




ECMAScript specification, in this case, doesn't refer to the preferred behavior to be implemented. The original browsers' behavior was to keep all the variables inside the closure, even those who were not referenced. In the case above, 'y' was kept in memory, creating a memory leak.

The good news is that as of this writing, modern browsers had implemented a very useful optimization and only referenced variables are now kept in memory by the internal method.

eval is evil

Ok, so browsers scan the function's values and keep only the referenced once. But what if the internal function makes use of eval(), would the browser smart enough to detect the referenced values?

 
var listFunc= [];

setInterval(function hello(){
var funcResult = (function parentFunc () {
    var x = 20;
    var y = 30;
    var sonFunc = function () {
        var text = "X value is: " + x;
        eval("alert(some_other_text)");
    }
    return sonFunc;
})();
listFunc.push(funcResult);  

},100);

In this case, it can be very difficult for the browser to detect the referenced variables. As a result if the function makes use of eval() the optimization won't work and all the parent function's variable will be kept in memory by the internal function.

Conclusion

Closures are very useful in Javascript, but using them requires the developers to be very careful. Although browsers are trying to prevent memory leaks they can do it only in certain circumstances. Keep references only to required variables and avoid using eval() inside closures because it will completely prevent browsers' optimization, completely exposing you to memory leaks.

Comments

The Best

From Layers to Microunits

The evolution of “Code Cohesion” and “Separation of Concerns” The software industry has recognized the values of “Separation of Concerns” and “Code Cohesion” for more than two decades. Many articles, books and software-thinkers have contributed methodologies to implement these important values. In this short article I’d like to compare the conservative “Layers” solution with a new approach, which I call “Microunits”, that can open new ways of solving software design challenges. Read more...

GetHashCode Hands-On Session

The following is a hands-on post meant to demonstrate how GetHashCode() and Equals() methods are used by .NET Framework under the hood. For the sake of simplicity I will refer to the popular hashed-base Dictionary type, although any other hash based structure will follow a similar behavior, if not the same one. After understanding this post you should be able to spot potential problematic behaviors and resolve them, prevent creation of unreachable items in dictionaries and improve CRUD actions performance on hash based structures. The Theory GetHashCode() is used to create a unique integer identifier for objects/structs. The hashcode can be used for two purposes: Programmatically, by developers, to distinguish objects/structs form each other (NOTE: Not recommended when the default .NET implementation is used, as it's not guaranteed to preserve the same hash between .NET versions and platforms) Internally, by .NET Framework, when using the object/struct as a key in a has...

The GoF Hot Spots - Bridge vs Strategy

As part of my "GoF Design Patterns - The Hot Spots" posts series, this post is focused on two Design Patterns: Bridge and Strategy . Although these two DPs are completely different, when googling them we encounter several common misconceptions that may make us think that Bridge and Strategy are similar or even same patterns. I am not sure why but one of the popular misconceptions is that these two DPs shares the same UML diagram. We will dig into the original GoF Design Patterns (aka: DP) description trying to figure out the real Hot Spots (aka: specific particular parts that differentiating them from each other) of these two DPs and the relationship between them. In order to maximize the clarity of this article, I used two conventions: Phrases inside [square brackets] are meant to help understanding GoF definitions Italic sentences are GoF's book citations Strategy GoF Definition "Define a family of algorithms [Classes that inherits from the ...