Header Ads Widget

Can closure lead to a memory leak in javascript?

To understand the memory leak, first try to understand How closure is formed?
If an outer function has a child function, it has access to the members of its outer environment. It means, the child function can have access to all the variables of its parent. It is because of the outer lexical scoping.

memory leak in javascript
        function parent(){
            var a = 10;
            function child(){
                return child;
            }
            return child;
        }
        var childRef = parent();
      

In the above example, when we execute the parent function, it returns the child function and childRef is referencing the child function. Because the child function is using var a = 10, it will be part of its lexical scope (means it can access it). Had there been no child function, a would have been destroyed by Garbage Collector after parent execution is over.

How does Garbage collection work in javascript?

Before we dive into the main problem of memory leaking, let's understand how garbage collection works in javascript?
When a javascript function execution is over, its variables are garbage collected. When we invoke that function again, those variables will be initialized again in the memory. Once the execution is over, they will be garbage collected. But if an Outer function has a child function, and even if outer function execution is over, the inner function has access to its parent environment (variables), because it forms a closure. Due to this closure, even though outer function execution is over, its variables will not be garbage collected. But these days, we have the enhanced javascript engine, which can find if those variables are used within child function or not. If they are not used within the child function, they will be garbage collected. GC implementation is engine dependant, which means the way chrome does the garbage collection can be different than safari or firefox. However, the end goal is the same- to not destroy the outer function variable because the child function forms a closure.

    function parent(){
      // a is used within child(), so can't be garbage collected
      var a = 10; 
      // b is unused variable & can be garbage collected
      var b = 20; 
      function child(){
          return a;
      }
      return child;
    }
    var childRef = parent();
      
Now, Let go into the problem.

Suppose there are a lot of variables in the parent function. Because child function form closure, all those variables will be within the scope of the child. So, even though the parent function execution is over they will be staying in the memory. If the child is not doing anything with those variables then they are unnecessarily occupying the memory. Suppose the parent function has an array with thousands of elements, it will lead to a memory leak.

        function parent(){
            var a = 10; 
            var badArr = new Array(1000000); 
            function child(){
                return a;
            }
            return child;
        }
        var childRef = parent();
      

in the above example, you can see that badArr is having 1 million empty indexes, and because it is withing the scope of child function (because of closure), it will lead to a memory leak.
Although smart browsers can detect if any variable is used within child function or not, if not then they destroy them.

    function child(){
      var tempArr = badArr; // tempArr is unused within child
      return a;
    }
      

If we modify the child function a bit and hold the badArr within a tempArr variable, even smart JS engines will not garbage collect it. Becasue, garbage collector will see it beinng referenced from child function.
NOTE: In the above example, child function is just referencing badArr not its value.

Algorithm behind Garbage collection

When a javascript program is executed, Javascript engine allocates memory for its valiables and functions. Once variables is used, it releases them from the memory. To accomplish this, Javascript use Mark and Sweep algorith. If I explain it in simple word - This algorithm start from the root and goes till the end of the leaf. It marks all the memory which is not referenced from anywhere. And finally releases those memory (which are marked).

    function parent(){
      var a = 10; 
      var badArr = new Array(1000000); 
     function child(){
       var tempArr = badArr;
     }
     return child;
    }
    var childRef = parent();
    

In the above example when Javascript engine start executing parent function, it encounters var a = 10;. It allocates a memory for it. Then it encounters var badArr = new Array(1000000); and allocates memory for badArr. Then it encounters return child;, child function reference is stored within childRef and memory is allocated to it. When garbage collector runs Mark and Sweep algorith, it marks var a as unused variable. It found var badArr referencecd within child function and leaves it. Finally it release the var a from memory as it is not referenced from anywhere.

Garbage collector in javascript

Conclusion:

Javascript functions have access to parents environment because of its outer lexical scope and closure. If a function is unnecessarily referencing its parent environment members, those referenced members will unnecessarily occupy space in memory. Garbage collector algorithm will not mark them as garbage, because they are within a closed scoped of the child function. Make sure that you do not leave any unused variables or any reference to outer function variables which is not used in the child.

Post a Comment

0 Comments