Guardians
This is a proposal, not an implemented fact; it is being discussed in bug 698463.
Guardians allow objects to be saved from garbage collection so that clean-up operations can be performed on them. Guardians avoid the more serious problems associated with traditional object finalizers: the application has full control over the timing of the clean-up operations, and the guarded objects remain fully alive until after they have been removed from the guardian's care.
In a Mozilla application, guardians can use the event loop to notify the application when an object has been proven to be reachable only through the guardian mechanism, and not via any other JavaScript objects, XPCOM references, or other roots.
R. Kent Dybvig, David Eby, and Carl Bruggeman first described guardians in their 1993 paper, Guardians in a generation-based collector; guardians have been implemented as part of Chez Scheme since roughly that time, as documented in The Chez Scheme User's Guide.
Guardians
A guardian protects a group of JavaScript objects from deallocation, and allows the system to determine when they would otherwise have been deallocated. The objects in a guardian's care are divided into two disjoint subgroups: "accessible" objects, and "inaccessible" objects. The "inaccessible" objects are those that the garbage collector have proven to be unreachable other than through guardians. The "accessible" objects are those for which this has not been proven: they are either still live --- reachable via non-guardian JavaScript objects and roots --- or the garbage collector has not yet noticed that they have become inaccessible.
Suppose your program has a heap that includes three objects:
We can create a guardian, and register two of the objects with it:
var guardian = new Guardian(); guardian.add(obj2); guardian.add(obj3);
This leaves obj1
alone, but adds obj2
and obj3
to guardian
's accessible set:
Suppose that, as the program runs, the last reference to obj1
goes away, and that the last reference to obj3
, other than the one in guardian
, goes away as well:
When the garbage collector notices this situation, it will silently free obj1
, but instead of freeing obj3
, it will move guardian
's reference to it to the "inaccessible" group:
Now, guardian
keeps obj3
alive until we call guardian
's next
method to retrieve it:
var saved = guardian.next();
This removes obj3
from guardian
's care altogether, and stores it in saved
:
(Guardians are iterators: if we try to get another object from the guardian now that its "inaccessible" set is empty, it throws a StopIteration
exception.) We can now clean up obj3
's state as needed, and then drop our last reference to it, so the next garbage collection can really free it:
Note that at no point does obj3
enter any special allocation state. The guardian's reference to obj3
is a strong reference, keeping obj3
and any objects it refers to alive until they are removed from the guardian and dropped. Once removed from guardian
, obj3
can be handed out to other JavaScript code, registered with a guardian again, or simply dropped. If the clean-up code itself puts obj3
in a "destructed" state—one where it no longer has the properties expected of a live instance of its type—it is simply the clean-up code's responsibility not to hand obj3
to code expecting a fully functioning object.
Image sources
Here are the SVG sources for the embedded diagrams above: