Counters memory

Memory

Understanding garbage collection and memory leaks is an advanced topic, but even beginners should know that there can be problems here. Correct use of a suitable framework is the simplest way to avoid memory leaks.

The code in the counters example indicates how to construct and use such a framework.

IE memory leaks

Internet Explorer, prior to IE8 (check) had two memory heaps, one for JavaScript and the other for the DOM. Each heap had its own independent garbage collector.

This means that if a DOM node d held a reference to a JavaScript object j and also that j held a reference to d then neither garbage collector could collect j or d. What’s worse, even when the page was unloaded IE did not reclaim this memory.

Thus, prior to IE8, JavaScript could cause Internet Explorer to leak memory. This lost memory could be reclaimed only by closing the browser! Closing the page was not enough.

Garbage collection

The JavaScript garbage collection deletes objects provide it can discover that they can never be used again. The simplest case is:

x = [1, 2, 3, 4, 5, 6, 7];
x = null;

The second assignment to x ensures that the original array (created by the array literal) can no longer be accessed, and so it can be garbage collected.

After the counters namespace anonyomous function has executed there are no global objects holding even indirect references to the function. Therefore it can and will be garbage collected. However, as we shall see, the execution context of the function continues.

The whole of the discussion here reduces to two things

  • The execution of the context of the namespace of anonymous function continues to exist after the function has completed execution.

  • If the line

    element.onclick = onclick_factory(models);
    

    were removed, then after the execution of the anonymous function all the JavaScript objects it created would be garbage collected.

The trick is to allow garbage collection to take place by releasing, when the time comes, all DOM reference to JavaScript objects.

Residue

The element DOM node continues to exist, as it can be reached from the document node. It has an onclick attribute, which is the function created by the onclick_factory, with models as the argument. So that function is not garbage collected and neither is models.

This is just as it should be. Anything that can be reached from the rendered web page is not garbage collected. It has to be there so that click has the desired effect.

The function element.onclick retains a reference to models just as surely as executing

var f = function(arg){ return [1, 2, 3, arg] };
var y = f(x);

causes y to retain a reference to the value of x.

Finally, models contains references to the Counter instances and thus, by the hidden prototype reference, to the counter prototype object.

The counter prototype object lies in the execution context of the anonymous function, and as it happend that keeps alive the whole of the execution context.

Reclaiming memory

Notice that the JavaScript holds only two reference to DOM nodes, namely document and example. However, the line of code

element = undefined;    // Release reference to DOM node.

means that the JavaScript no longer holds a reference to element.

The DOM node example holds a reference, via its onclick function, to the JavaScript on the page, and in particular to the Counter instances. This cannot be avoided, because we want certain DOM nodes to change the state of the counters.

However, the converse is not true. We can write the JavaScript code so that it has but one reference to a DOM object, namely the document node held for example as a property of the global object.

Summary

To avoid the IE memory leaks the trick is to ensure that, when the page unloads, there is nothing that is keeping the garbage is alive. If we execute

element.onclick = undefined

then there is nothing on the page that is keeping our JavaScript code alive. And once all the JavaScript is garbage collected then there’s nothing to prevent all the DOM notde being garbage collected.

The key principle in this strategy is that the page unload event should unbind all JavaScript event handlers and other data attached to the page. This will ensure that the JavaScript is garbage collected, and hence there is nothing to obstruct garbage collection of the DOM nodes.

Clearly, this strategy requires us to keep track of what we add to the DOM. Delegation makes this much easier to do.