[pypy-dev] The fate of gc-del

Armin Rigo arigo at tunes.org
Sun Aug 11 09:52:55 CEST 2013


Hi all,

I'm trying again to look at the gc-del branch, but I'm kind of
failing.  The current state is:

    http://buildbot.pypy.org/summary?branch=gc-del

The failures are all more or less obscure.  The issues all may have to
do with subtly broken things in the finalizer ordering code.  But now
I believe that the attempted implementation was a bad idea.

For reference: you call "rgc.register_finalizer(method)" on objects
where you want a finalizer to be called (instead of "def __del__()",
which is now limited to "lightweight" destructors).  It's a good idea
by itself because (1) you can register a finalizer only after the
object is ready, and not have to care for seeing half-initialized
objects in the finalizer; and (2) you can register a finalizer at any
time, or not at all, on various instances of the same class, which is
very convenient for implementing app-level objects that may or may not
have a user-level __del__ method.

The issue is that the finalizers (particularly the app-level ones)
should only be called at known points in time, e.g. between bytecodes,
and not from random places.  I tried to do this: if a finalizer raises
"FinalizeLater", then it suspends calling finalizers --- both the
current one and all future ones.  Later, between bytecodes, we call
rgc.progress_through_finalizer_queue() to resume.  This looks innocent
enough, but it's a major mess.  First in test runs: because the
finalizer queue is not attached to any space, and raising
FinalizeLater suspends calling any finalizer from there, in order to
maintain the correct order.  Also, I suspect, in real runs.  We're
getting cases where the app-level __del__() is not called and I'm
really unsure why, but I suspect that some finalizer raises
FinalizeLater without making sure that we'll later call
rgc.progress_through_finalizer_queue().  Basically, this API looks
broken now.

It becomes messy when you consider that some helpers in rpython.rlib
really need rgc.register_finalizer(), like rmmap.  These helpers don't
know about the space.  The hack of the previous paragraph was an
attempt to still have rmmap objects finalized in the globally correct
order.

Help! :-)  Any cleaner ideas welcome!  Would it make sense to *not*
call automatically any finalizer, and instead require that the RPython
program calls rgc.flush_finalizer_queue() regularly?  Maybe with some
minimal signal-like event from the GC to mean "there are finalizers
now"?  It would seem closer to what e.g. Java does, which just puts
finalizable objects on a queue from the GC.


A bientôt,

Armin.


More information about the pypy-dev mailing list