[Patches] [ python-Patches-477059 ] __del__ on new classes vs. GC
noreply@sourceforge.net
noreply@sourceforge.net
Thu, 01 Nov 2001 09:03:28 -0800
Patches item #477059, was opened at 2001-10-31 20:13
You can respond by visiting:
http://sourceforge.net/tracker/?func=detail&atid=305470&aid=477059&group_id=5470
Category: Core (C code)
Group: None
Status: Open
Resolution: None
Priority: 5
Submitted By: Guido van Rossum (gvanrossum)
Assigned to: Neil Schemenauer (nascheme)
Summary: __del__ on new classes vs. GC
Initial Comment:
Neil, excuse me for the assignment. You can reassign
this to Tim if you don't have time; I know *I* won't
get to it in time for 2.2b2.
I recently added __del__ for new-style classes, but I
believe this would require the same kind of exception
from the GC code as classic instances with a __del__
handler. Of course, it's a bit more difficult since
*any* heap-based type can have a __del__ handler...
----------------------------------------------------------------------
>Comment By: Tim Peters (tim_one)
Date: 2001-11-01 09:03
Message:
Logged In: YES
user_id=31435
In Guido's example, if we assume the cycle will never ever
get broken by the user, then reclaiming the X instances
would be cool: we know they're trash, and they're not
themselves in a cycle.
The rub is that it's a bad assumption -- despite that the
cycle is unreachable, it can still be gotten at, by the
user, via gc's list of unreclaimable trash. My model for
what people should do is:
1. Don't create cycles with __del__ methods.
2. If you do, cleam 'em up yourself (and gc exposes
the unreclaimable cycles, so that's quite doable even
*after* the cycles become "unreachable").
So long as we expose unreclaimable cycles, nothing in a
cycle is *truly* unreachable, and that makes deleting the X
instances by magic dangerous (the user may break the cycle
themself, and a destructor in one of the cycle members may
need to access an intact X).
----------------------------------------------------------------------
Comment By: Neil Schemenauer (nascheme)
Date: 2001-11-01 08:45
Message:
Logged In: YES
user_id=35752
We seem to have our messages passing each other in flight. :-)
In your example you don't see X.__del__ because the C
instances are never freed. We can't call tp_clear on
either of the C instances because we can't choose an ordering
that ensures their __del__ methods will work. For example, if
we clear "a" first but b.__del__ uses some attributes of "a"
then we will get an exception. I suppose we could have an
option that says "call tp_clear on unreachable objects even
if they have finalizers".
----------------------------------------------------------------------
Comment By: Guido van Rossum (gvanrossum)
Date: 2001-11-01 08:39
Message:
Logged In: YES
user_id=6380
I guess I misunderstood what you said before. Never mind.
----------------------------------------------------------------------
Comment By: Neil Schemenauer (nascheme)
Date: 2001-11-01 08:30
Message:
Logged In: YES
user_id=35752
Anything with a finalizer (i.e. __del__ method) or reachable
from a finalizer does not get tp_clear called on it. We
discussed this at length when the GC was being implemented.
I don't think anything has changed since then but I'm open
to more discussion.
----------------------------------------------------------------------
Comment By: Guido van Rossum (gvanrossum)
Date: 2001-11-01 08:16
Message:
Logged In: YES
user_id=6380
I'll leave this in your & Tim's capable hands.
I don't see any proof that tp_clear is being called; or
maybe there's no tp_clear for new-style instances. I ran
this script:
import gc
class C(object):
def __del__(self): print "C.__del__"
class X(object):
def __del__(self): print "X.__del__"
a = C()
a.x = X()
b = C()
b.x = X()
a.b = b
b.a = a
del a, b
gc.collect()
Before the change I checked in this morning (but after
adding __del__, obviously), this printed
X.__del__
C.__del__
C.__del__
X.__del__
Now it prints nothing. I somehow had expected this
X.__del__
X.__del__
since the X instanes are not contributing to the cycle --
they are merely hanging off its sides. I probably
misunderstand something.
----------------------------------------------------------------------
Comment By: Neil Schemenauer (nascheme)
Date: 2001-11-01 07:50
Message:
Logged In: YES
user_id=35752
This is not too serious of a problem and shouldn't be hard to
fix. If we don't do anything then the result will be that
unreachable new-style classes will get tp_clear called on
them even if they have __del__ methods. As Tim suggests,
fixing this should be a matter of removing some
PyInstance_Check tests.
----------------------------------------------------------------------
Comment By: Guido van Rossum (gvanrossum)
Date: 2001-11-01 06:26
Message:
Logged In: YES
user_id=6380
Thanks -- I thought it would probably shallow but wasn't
sure. I've fixed this now.
Do I understand correctly that objects with a __del__
attribute are not GC'ed at all (if part of a cycle)? Isn't
that sad? Shouldn't we at least attempt to recover the
memory without calling the finalizers?
----------------------------------------------------------------------
Comment By: Tim Peters (tim_one)
Date: 2001-10-31 22:13
Message:
Logged In: YES
user_id=31435
Guido, I expect this is shallow, confined to move_finalizers
(). It's looking for objects that both (a) have
a "__del__" attr, and (b) pass PyInstance_Check(). An
instance of a new-style class with __del__ passes the
former test but not the latter, and I believe that's all
the repair needed (but am blanking out on exactly what
should be checked instead -- it will occur to me overnight
<wink> -- I assume the existing PyInstance_Check is really
just trying to avoid the expense of general
PyObject_HasAttr when the latter has no chance of
succeeding).
----------------------------------------------------------------------
You can respond by visiting:
http://sourceforge.net/tracker/?func=detail&atid=305470&aid=477059&group_id=5470