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.
Hide Copy Code
var globalVal = "Hi";
function changeValue () {
var differentVal = "Hello";
function swapValues() {
var tempVal = differentVal;
differentVal = globalVal;
globalVal = tempVal;
}
swapValues ();
}
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:
Hide Copy Code
var objectA = new object();
objectA.value = 10;
var objectB = new object();
objectB.value = objectA.value;
- 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:
Hide Copy Code
var objectA = new object();
objectA.newobject = objectB;
var objectB = new object();
objectB.newobject = objectA;
- 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
Hide Copy Code
function outer()
{
var someLargeData = "abcdefghijkl mnopqrstuvwxyz abcdefghijkl mnopqrstuvwxyz
abcdefghijkl mnopqrstuvwxyz";
function inner()
{
}
return fromInnerFunction;
}
Solution
Hide Copy Code
function outer()
{
var someLargeData = "abcdefghijkl mnopqrstuvwxyz abcdefghijkl mnopqrstuvwxyz
abcdefghijkl mnopqrstuvwxyz";
function inner()
{
}
someLargeData = null;
return fromInnerFunction;
}
Scenario 2
Problem
Hide Copy Code
function f()
{
data = "some value";
}
function f()
{
window.data = "some value"
}
Solution
Hide Copy Code
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