Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Garbage Collection and Memory Management in JavaScript

0.00/5 (No votes)
30 Oct 2016 1  
This article discusses about the relation between memory management and garbage collection

Introduction

This is a brief article on Garbage collection in JavaScript. I was going through some good books and some sites. I found out some informative details about garbage collection in JavaScript. I thought of putting all the details in one place.

Background

  • JavaScript is a garbage collected language. The managed environment here is the browser which takes all the decisions.
  • In languages like C or C++, you have to take care of the memory management on your own, like allocation and deallocation of memory.
  • In JavaScript however, there is no need to take of garbage collection. The garbage collector takes care of this for you.
  • Before reclaiming the memory of a variable or an object, its life time and further usage is determined. If the variable is no longer required, its memory is reclaimed for further use.
  • A variable or an object gets garbage collected when it is not in further use. This is done by looking at the execution context of that variable.

We will look briefly at what is the execution context of a variable.

Execution Context of a Variable

The execution context of a variable defines as to what other data it can access.

There are 2 types of contexts:

  • Global Context
  • Local Context

The below code example (Inspired from Wrox.Professional JavaScript) explains the difference between a local and a global context.

/* This is a global context, lets name it "G" */
var globalVal = "Hi";

 function changeValue () {
    /* This is the local context of function "changeValue", lets name it "CV" */
    var differentVal = "Hello";
    
    function  swapValues() {
      /* This is the local context of the function "swapValues" lets name it "SV" */
      var tempVal = differentVal;
      differentVal = globalVal;
      globalVal = tempVal;
      // The variables "globalVal", "differentVal" and "tempVal" can be accessed here
    }
    // The variables "globalVal", "differentVal" are accessed here.
    
    swapValues ();
 }
 
 // The variable globalVal can be accessed here
 changeValue ();

As per the code, we have divided the execution contexts as below:

  • Global Context: Named as "G".
  • Local Context: This is subdivided into the local context for function "changeValue" named as "CV" and the context for the function swapValues named as "SV".
  • After this, a scope chain is created which tells the accessibility of the variables. This helps the garbage collector to know which variables can be used and which can be freed.
  • Looking at the below image will bring more clarity:

  • If you look at the image above, you will see that the variables which are GC'd as per lowest priority of usage will be:
    • tempVal (This belongs to the context "SV")
    • differentVal (This belongs to the context "CV")
    • globalVal (This belongs to the context "G")
  • The variable "tempVal" is checked to see if it is required further. Its scope and usage ends in the context "SV" itself and won't be used again and hence it is freed the moment the scope of the function is over.
  • The scope of the context "SV" has now finished and the scope of "CV" starts as the function execution of "swapValues()" is over and the execution is back again in "changeValue()".
  • Now, the variable "differentVal" is GC'd when the execution of the function "changeValue" is over. After this, the execution comes back into the global context, i.e. "G".
  • Eventually the variable "globalVal" is also GC'd as you close the webpage.

Strategies of Garbage Collection

Mark and Sweep

  • If the variable under execution is in context, it is marked by the garbage collector, its memory will never be freed as long as it is in context. Once it is out of context, it is again flagged so as to mark it as out of context.
  • Hence we can derive that there might be 2 lists which could be maintained by the browser, "in-Context" and "Out-Of-Context".
  • The Garbage collector marks all the variables which have memory allocated, it checks for the context of the variables whether "in-context" or "Out-Of-Context".
  • The "in-context" variables are not garbage collected as they are in the scope of execution. The "out-of-context" variables are garbage collected and their memory is reclaimed by the garbage collector.

Reference Counting

  • This is another less significant method of garbage collection employed. The basic principle of this is to keep a track of the number of references made to a variable.
  • To track the number of references, a reference counter is maintained.
  • For example:
    var objectA = new object();
    objectA.value = 10;
     
    var objectB = new object();
    objectB.value = objectA.value; //object B references the value of A	
  • In this example, the value of object A is referenced by B. Hence, the counter is incremented. If such similar references are made by any other object, the counter is incremented.
  • Now, suppose the value property of objectB (which is referencing the value of objectA) is overwritten or changed, the counter is decremented.
  • The garbage collector checks for this count, if it is zero, the memory for that object is reclaimed as there are no further references to it.
  • This method has a major disadvantage. Consider the below code:
    var objectA = new object();
    objectA.newobject = objectB; //object A references Object B
    
    var objectB = new object();
    objectB.newobject = objectA; //object B references Object A
    
  • The above code has created a problem of circular reference. If you notice, the value of the reference counter will be the same for both the objects.
  • Unless the objects are destroyed manually, their memory will not be freed and what if the function executing this code is called recursively?
  • It will lead to a lot of wastage of memory. So, the solution to the problem would be obviously to make the objects in the above code NULL.
  • Such corner cases would have to be taken care in this kind of methodology, however this would have been taken care in Mark and Sweep method automatically once the above code is out of scope.

Hence, our aim should be to manage the memory in such a way that we avoid the above mentioned problems. The forthcoming topics discuss the issue and solution related to memory management.

Memory Management

  • When the data is no longer necessary, it is best to set its value to NULL, especially if you have declared a global object. At the end, after your job is done, you make that global object NULL.
  • Memory leak is an other issue, suppose you have a circular reference (as we discussed above) and you do a page unload / Close / restart the page, even then this problem is not solved. This would more frequently happen in the versions of Internet Explorer less than 8. The solution is again to make the object NULL after your job is done.
  • It is always good to benchmark the memory usage while writing lengthy programs because a single memory leak could multiply if there is recursion in the code.
  • The memory allocated / usage is lesser as compared to the desktop applications which are developed, hence this is a good advantage as the system won't hang or crash.
  • The main cause of memory leaks in garbage collected languages is unwanted references.
  • The scenarios below will give some idea of how to avoid memory leaks.

Scenario 1

Problem

  /* Below is a memory leak prone function the data stored in "someLargeData" will persist in the memory 
  until the function inner() is active */
function outer()
{
  var someLargeData = "abcdefghijkl mnopqrstuvwxyz abcdefghijkl mnopqrstuvwxyz 
                       abcdefghijkl mnopqrstuvwxyz";
  
  /* Use the data stored in variable "someLargeData" in the function "inner" */
  function inner()
  {
    // Process the data stored in variable "someLargeData"
  }

  return fromInnerFunction;
}

Solution

/* After the function inner is over make the "someLargeData" variable NULL.
  The above function causes "someLargeData" to occupy a lot of memory, but the below code
  causes the "someLargeData" to not occupy a large memory  */
function outer()
{
  var someLargeData = "abcdefghijkl mnopqrstuvwxyz abcdefghijkl mnopqrstuvwxyz 
                       abcdefghijkl mnopqrstuvwxyz";
  
  /* Use the data stored in variable "someLargeData" in the function "inner" */
  function inner()
  {
    // Process the data stored in variable "someLargeData"
  }

  someLargeData = null;
  return fromInnerFunction;
} 

Scenario 2

Problem

/* Below function simply uses a variable "data" without declaring it */
function f()
{
  data = "some value";
}

/* The variable "data" actually expands to "window.data" becoming an undeclared global variable */
function f()
{
  window.data = "some value"
}

Solution

/* Add the "use strict" to give an error to avoid accidental globals */
function f()
{
  "use strict";
  data = "some value";
}  

Finally, we can avoid or minimize memory leaks by using memory profiling tools to find out memory leaks, especially when you write a big application.

References and Further Reading

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here