Something I found...
11.7 Garbage Collection
In any programming language in which you can dynamically create new objects
(such as with the new operator in JavaScript) there must be some form of
"garbage collection"--a way of reclaiming the memory occupied by objects
that are no longer in use. In C and C++, garbage collection is manual--the
programmer explicitly decides when to free memory for reuse. In Java, on the
other hand, garbage collection is handled automatically--the system can
detect when objects are no longer in use and free them appropriately.
JavaScript also supports automatic garbage collection. In Internet Explorer
3.0, garbage collection is implemented in a technically sound way and you
don't have to understand any of its details--it is enough to know that when
your objects are no longer in use, the memory they occupy will automatically
be reclaimed by the system. Navigator 4.0 will also have a perfectly
transparent garbage collection scheme like this. Unfortunately, garbage
collection in earlier versions of Navigator is less than perfect. In
Navigator 3.0, it is pretty good, but requires you to be aware of a couple
of issues. In Navigator 2.0, garbage collection is seriously flawed, and you
must take a number of steps to avoid crashing the browser! The following
subsections provide the details.
Reference Counting in Navigator 3.0
In Navigator 3.0, garbage collection is performed by reference counting.
This means that every object (whether a user object created by JavaScript
code, or a built-in HTML object created by the browser) keeps track of the
number of references there are to it. Recall that objects are assigned by
reference in JavaScript, rather than having their complete value copied.
When an object is created and a reference to it is stored in a variable, the
object's reference count is 1. When the reference to the object is copied
and stored in another variable, the reference count is incremented to 2.
When one of the two variables that holds these references is overwritten
with some new value, the object's reference count is decremented back to 1.
If the reference count reaches zero, then there are no more references to
the object, and since there are no references to copy, there can never again
be a reference to the object in the program. Therefore, JavaScript knows
that it is safe to destroy the object and "garbage collect" the memory
associated with it.
This reference-counting scheme has some important implications. (These
implications are also true of the Internet Explorer garbage collector, but,
as we'll see, they are not true of the garbage collection scheme in
Navigator 2.0.) If JavaScript code running in a window creates an object,
and a reference to that object is stored in a variable of another window,
then that object will continue to exist even after the window that created
it is closed, or loads in a different page. The original reference to the
object is lost, but since a reference still exists from another window, the
object will not be garbage collected.
Perhaps a more surprising implication is that a top-level browser window may
be closed by the user or by JavaScript code, but the Window object
associated with it may continue to exist. This occurs when a variable in one
window contains a reference to the window that is closed. Since there is
still a reference to the Window object, that object cannot be garbage
collected. Note, however, that many of the methods and properties of a
Window object that is closed cannot be meaningfully used. In Navigator 3.0,
you should be sure to check the closed property (a Boolean value) of any
Window object before using its properties or methods, if there is any chance
that it could have been closed.
Shortcomings of Garbage Collection by Reference Counting
As you may already be aware, there are some shortcomings to using reference
counting as a garbage collection scheme. In fact, some people don't even
consider reference counting to be true garbage collection, and reserve that
term for algorithms such as "mark-and-sweep" garbage collection. The
computer science literature on garbage collection is large and technical,
and we won't get into it here. For our purposes it is enough to know that
reference counting is a very simple form of garbage collection to implement,
and it works fine in many situations. There are situations, however, in
which reference counting cannot correctly detect and collect all "garbage",
and you need to be aware of these.
The basic flaw with reference counting has to do with cyclical references.
If object A contains a reference to object B and object B contains a
reference to object A, then a cycle of references exists. A cycle would also
exist, for example, if A referred to B, B referred to C, and C referred back
to A. In cycles such as these, there is always a reference from within the
cycle to every element in the cycle. Thus, even if none of the elements of
the cycle has any remaining references, their reference count will never
drop below one, and they can never be garbage collected. The entire cycle
may be garbage, because there is no way to refer to any of these objects
from a program, but because they all refer to each other, a
reference-counting garbage collector will not be able to detect and free
this unused memory.
This problem with cycles is the price that must be paid for a simple,
lightweight, portable garbage collection scheme. The only way to prevent
this problem is by manual intervention. If you create code in which A refers
to B, B refers to C, and C refers to A, then you must be able to recognize
that you've created a cycle, and take steps to force the cycle to be garbage
collected when it is no longer needed.
When you know that the objects in your cycle are no longer in use, you can
force them to be garbage collected by breaking the cycle. You can do this by
picking one of the objects in the cycle and setting the property of it that
refers to the next object to null. For example, suppose that A, B, and C are
objects that each have a next property, and the value of this property is
set so that these objects refer to each other and form a cycle. When these
objects are no longer in use, you can break the cycle by setting A.next to
null. This means that object B no longer has a reference from A, so its
reference count can drop to zero and it can be garbage collected. Once it
has been garbage collected, then it will no longer refer to C, so its
reference count can drop to zero and it can be garbage collected. Once C is
garbage collected, A can be garbage collected.
Note, of course, that none of this can happen if A, B, and C are stored in
global variables in a window that is still open, because those variables A,
B, and C still refer to the objects. If these were local variables in a
function, and you broke their cycle before the function returned, then they
could be garbage collected. But if they are stored in global variables, they
will remain referenced until the window that contains them closes. In this
case, if you want to force them to be garbage collected you must break the
cycle and set the variables to null:
A.next = null; // break the cycle
A = B = C = null; // remove the last remaining external references
Per-Page Memory Management in Navigator 2.0
The garbage collection scheme in Navigator 2.0 is much simpler than that in
Navigator 3.0, and, unfortunately, it is inadequate for the needs of
JavaScript programs that use multiple windows and frames. In Navigator 2.0,
all objects created by JavaScript code running in any particular window
allocate memory from a pool of memory owned by the window. Then, when the
window is destroyed, or when the document (containing the JavaScript
program) displayed in the window is unloaded, the entire pool of memory is
freed at once. No memory is freed until then.
With this garbage collection scheme, all memory allocated by the JavaScript
running in a window can be freed in a single stroke. It is a simple and
efficient scheme to implement. Unfortunately, it suffers from two major
drawbacks.
First, if an object is created in one window, and then a reference to that
object is stored in a variable in a second window, that object will be
destroyed when the first window moves on to a new page, despite the fact
that there is still an active reference to it from the other window. If this
other window attempts to use this reference to the destroyed object, an
error will result, possibly crashing the browser! This is an especially
pernicious problem, because doing something as simple as assigning a string
can cause this problem. Consider the following code:
newwin = window.open("", "temp_window");
newwin.defaultStatus = "temporary browser window".
The defaultStatus property is set to a string "owned" by the original
window. If that window is closed, the string will be destroyed and the next
reference to defaultStatus will go looking for a non-existing string.
The second problem with this scheme is that if a window never unloads, the
memory associated with it will never be freed. For a page that runs some
JavaScript once and then is static, this is not a problem. But consider a
page that performs a status-bar animation, for example. If it updates the
status bar several times a second for a long time, the memory consumed by
that page will grow and grow. Another example occurs with the use of frames.
One frame might serve as a navigation window, with controls that allow a
user to easily browse a large site in other frames or other windows. These
other frames and windows may load and unload pages frequently, freeing
memory. But the navigation frame itself remains the same, and the memory
associated with it is not freed. Depending on how the event handlers are
written, there is a good chance that each time the user interacts with the
navigation controls some new string or object will be created, and no memory
will ever be freed. Eventually, the browser will run out of memory, and may
well crash.
Workarounds for Navigator 2.0
It is possible to compensate, somewhat, for these memory management problems
in Navigator 2.0. For the problem of memory not being released until the
page is unloaded, the solution is simply to be careful about how much memory
your scripts consume. If your page loops a lot or does a repetitive
animation, look very carefully at the code that is executed over and over,
and minimize the number of objects created on each iteration. Similarly, if
you write a script that the user may use frequently without ever unloading,
be sure to keep careful tabs on your memory usage.
Note that string manipulation is a big memory sink--each time you call a
method on a string object, a new string object is generally created for the
result. The same is true for string concatenation with the + operator.
For the problem of dangling references from one window to destroyed objects
that were owned by another, one solution is to avoid programs that rely on
inter-window references. Another solution is to be sure to make copies of
all strings and other objects that are passed from one window to another.
Suppose that in window 1, you want to set the defaultStatus property of
window 2, as we saw earlier. If you do this directly with code in window 1,
then window 2 will contain a reference to an object owned by window 1. But,
if you call a function in window 2 to do the assignment, and make sure that
the function makes a copy of the object, then the object assigned in window
2 will be owned by window 2. You could, for example, ensure that window 2
contains a definition of the following function:
function set_string_property(name, value)
{
// Assign a property to this window, using associative array notation.
// We add the empty string to the value to force JavaScript to make
// a copy. If this function is called from another window, we won't
// own the value string, but by making a copy, we do own the result.
self[name] = value + "";
}
With this function defined, you could then set the property from window 1
with a line like the following:
window2.set_string_property("defaultStatus", "temporary browser window");
_______________________________________________
Dynapi-Dev mailing list
[EMAIL PROTECTED]
http://lists.sourceforge.net/lists/listinfo/dynapi-dev