view source/counters-memory.rst @ 213:0ea90a1819c2 default tip

Custom theming
author Radomir Dopieralski <radomir.dopieralski@allegro.pl>
date Wed, 27 Jun 2012 16:35:54 +0200
parents 4e6cfa066d1a
children
line wrap: on
line source

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:

   .. code-block:: javascript

      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

  .. code-block:: javascript

     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

   .. code-block:: javascript

      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

   .. code-block:: javascript

      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

.. code-block:: javascript

   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.