On Sun, Jun 19, 2011 at 06:01:33PM -0700, [email protected] wrote: > > First, change VTable's destructor to a no-op, so that it no longer throws an > > error. As soon as we do this, tests will start passing again. > > > > Second, perhaps we should change lucy_Memory_wrapped_free() to a no-op once > > we > > enter the global destruction phase. That way, even when SegWriter gets > > reclaimed first, there's still a real object at indexer->seg_writer instead > > of > > a dangling pointer. > > Or you could use END blocks, as you suggested for KinoSearch::Simple (at > least two renamings ago), and for which I wrote a patch that you applied. > > The same technique could be applied to other classes with a has-a > relationship.
Hmm, I think Lucy::Simple is a special case. It's one of only two classes where we're counting on the destructor to do something important -- run Indexer's commit() method, flushing buffered adds to disk. It's best practice to avoid relying on object clean up for crucial behaviors -- and this change to Perl illustrates exactly why. Under tracing garbage collection, it's even more important, because finalizers (as opposed to destructors) always fire non-deterministically. To my mind, any object that has made it through to global destruction time because of leaked reference counts is hosed. It's not worth trying to impose a deterministic scheme at that point -- too many opportunities for error. (What order will the END blocks run in?) The other class with an important destructor is OutStream, which flushes buffered writes by calling FH_Write(self->file_handle). We should probably remove that behavior. It's about to become dangerous -- if the FileHandle's destructor fires before the destructor of the OutStream that wraps it, the OutStream will be attempting to write to a closed stream. > In any case, this second fix that you are suggesting is unrelated to the > Perl change I mentioned above. (Prior to that change, the VTable object > would be freed, but without its destructor called.) Think of each VTable has having two parts: a Clownfish object, and a Perl object. They point at each other in a circular reference. However, the Clownfish object delegates reference counting to the Perl object, so the pair of objects share a single unified refcount. When that refcount falls to 0, the Perl destructor gets called. For current stable Perl behavior, during global destruction the Perl SV* gets freed, but since the destructor is never called, the Clownfish object leaks and is left behind. It's freed when the OS cleans up the process. Marvin Humphrey
