On Tue, 2004-09-21 at 19:22, bulia byak wrote:
The problem? It saves a pointer to itself as a parameter, so the collector sees there is still a pointer to it and never collects it or any other objects it points to.
Wouldn't it be more logical if GC simply disregarded any pointers from an object to _itself_ and not count them as pointers?
It does.
The finalization callback "user data" pointers are saved elsewhere.
Actually, I'm oversimplifying a lot -- a mark-and-sweep collector doesn't care who points to what or how many they are, just whether an object is directly or indirectly accessible from a set of "root" memory locations by following pointers.
The callback data pointers get stored in a place that's accessible from one of the roots. This makes sense normally, since you don't want the callback's data to get collected prematurely.
Calling C++ destructors is slightly outside the normal usage of the finalization facility.
It's documented that you aren't supposed to pass a pointer to the finalizable block itself there directly. I missed that the first time I read the documentation.
The correct approach is to save an integer offset relative to a base address instead, as is done by the (roughly equivalent) gc_cleanup class that ships with libgc.
This doesn't strike me as something particularly elegant. Pointers to integers and back sounds like a crime in C, for obvious reasons. Even if you don't try to do arithmetic on them.
Storing a pointer as an integer wouldn't hide it from the collector anyway.
What I'm doing now is storing an integer offset (in bytes) from the start of the allocated block (which the collector tells us at finalization time), instead of a direct pointer.
This is just so we can find the C++ vtable entry for the destructor; a lot of the "magic" here is really imposed upon us by C++.
-mental