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

Closures in C# vs JavaScript -
Same But Different

Closure in a Nutshell Closures are a Software phenomenon which exist in several languages, in which methods declared inside other methods (nested methods), capture variables declared inside the outer methods. This behavior makes captured variables available even after the outer method's scope has vanished.

The following pseudo-code demonstrates the simplest sample:
Main() //* Program starts from here { Closures(); } AgeCalculator() { int myAge = 30; return() => { //* Returns the correct answer although AgeCalculator method Scope should have ordinarily disappear return myAge++; }; } Closures() { Func ageCalculator = AgeCalculator(); //* At this point AgeCalculator scopeid cleared, but the captured values keeps to live Log(ageCalculator()); //* Result: 30 Log(ageCalculator()); //* Result: 31 } JavaScript and C# are two languages that support…

Formatting Data with IFormatProvider & ICustomFormatter

This post provides an internal overview of IFormatProvider & ICustomFormatter interfaces, and they way they are handled by .NET.

IFormatProvider is a .NET Framework Interface that should be used, by implementing its single public object GetFormat(Type) method, when there is a need to implement custom formatting of data like String and DateTime.

The public object GetFormat(Type) method simply returns an object that in turns is available to supply all available information to continue the formatting process. The Type passed in by the Framework is meant to give the implementor a way to decide which type to return back. Its like a Factory Method Design Pattern where the "formatType" is the type expected to be returned.
class MyProvider : IFormatProvider { public object GetFormat(Type formatType) { object result = null; //* Factory Method if (formatType == typeof( ICustomFormatter)) //* Some object, will be disc…

Design API for Multiple Different Clients

Today I want to talk about common design challenges related to architecture of robust APIs, designed to be consumed by multiple clients with different needs.

Our use case is the following: We need to build a N-Tier Web REST/SOAP API that is supposed to read/write data from a DB, perform some processing on that data and expose those methods to our API consumers.

In addition we have multiple different API clients each with different needs, meaning we can't just expose a rigid set of functions with a defined group of DTOs (Data Transfer Objects).
DTO vs POCO Before start diving I want to explain shortly the difference between these two controversial concepts.
DTO Objects that are designed to transfer data between edges (i.e. between processes, functions, server & clients etc'). Typically DTOs will contain only simple properties with no behavior.
POCO Objects that are designed to reflect the internal business data model. For example if you have an eCommerce platform you will…