[vtk-developers] Disturbing garbage collection behavior.

Moreland, Kenneth kmorel at sandia.gov
Wed Mar 2 16:57:28 EST 2005


I have recently run into some behavior from the garbage collector that I
consider erroneous.  Consider two VTK objects, A and B, that are garbage
collected and point to each other.  Furthermore, assume that the only
reference to B is from A (whereas A has multiple references to it).
Consider what happens when a method in A executes the following code:

    A->PointerToB->UnRegister(this);
    A->PointerToB = NULL;

The intent of the code is obviously meant for A to drop its reference to
B.  However, it causes problems.  When UnRegister is called on B, its
reference count drops to 0 and its destructor is called.  We can assume
that B is a well behaved object that unregisters all of its references
in its destructor.  When it unreferences A, the garbage collector is
run.  The garbage collector picks up A's reference to B (which has not
yet been obliterated) and bad things happen.  In one instance I had the
garbage collector code fail an assert.  In another instance I have had
the "B" object destructed twice.  In either case (particularly the
latter) the problem code is not immediately apparent.  I have attached
some test code that exercises this problem.

I think the garbage collector can be corrected by maintaining a set of
objects that are in the process of destruction.  Whenever a link to an
object in the process of destruction is encountered, it can be ignored
with the assumption that it is about to be obliterated as in the code
above.  I can think of no down side to this approach.

There are those that will probably argue that this is technically not a
bug (which is why I have not yet submitted a bug report).  Technically,
the garbage collector is doing its job correctly, and the user has made
the mistake of keeping a pointer around after it has been destroyed and
then reporting it to the garbage collector.  The "correct" code would be

    vtkObjectBase *tmp = A->PointerToB;
    A->PointerToB = NULL;
    tmp->UnRegister(this);

However, I find this latter construction less clear (from a human
readability standpoint) than the original code.  Also, as a programmer,
I will never write the second construction unless I am actively thinking
about which variables are garbage collected (which I am not most of the
time).  What do other people think?

-Ken

   ****      Kenneth Moreland
    ***      Sandia National Laboratories
***********  
*** *** ***  email: kmorel at sandia.gov
**  ***  **  phone: (505) 844-8919
    ***      fax:   (505) 845-0833
-------------- next part --------------
A non-text attachment was scrubbed...
Name: TestGarbageCollector2.cxx
Type: application/octet-stream
Size: 4849 bytes
Desc: TestGarbageCollector2.cxx
URL: <http://public.kitware.com/pipermail/vtk-developers/attachments/20050302/e30cc19a/attachment-0001.obj>


More information about the vtk-developers mailing list