Garbage collection of recursive inner function
Diez B. Roggisch
deets at nospam.web.de
Mon Aug 4 14:08:29 EDT 2008
from.future.import at gmail.com schrieb:
> Hi,
>
> I encountered garbage collection behaviour that I didn't expect when
> using a recursive function inside another function: the definition of
> the inner function seems to contain a circular reference, which means
> it is only collected by the mark-and-sweep collector, not by reference
> counting. Here is some code that demonstrates it:
>
> ===
> def outer():
>
> def inner(n):
> if n == 0:
> return 1
> else:
> return n * inner(n - 1)
>
> return 42
>
> import gc
> gc.set_debug(gc.DEBUG_SAVEALL)
> print outer()
> gc.collect()
> print gc.garbage
> ===
>
> Output when executed:
> $ python internal_func_gc.py
> 42
> [<cell at 0xb7dec3ec: function object at 0xb7dbd3ac>, (<cell at
> 0xb7dec3ec: function object at 0xb7dbd3ac>,), <function inner at
> 0xb7dbd3ac>]
>
> Note that the inner function is not called at all, it is only defined.
> If the inner function is moved outside the scope of the outer
> function, gc.garbage will be empty. If the inner function is inside
> but not recursive, gc.garbage will also be empty. If the outer
> function is called twice, there will be twice as many objects in
> gc.garbage.
>
> Is this expected behaviour? Collecting an object when its refcount
> reaches zero is preferable to collecting it with mark-and-sweep, but
> maybe there is a reason that a circular reference must exist in this
> situation. I want to check that first so I don't report a bug for
> something that is not a bug.
The reference comes from the closure of inner. And inner is part of the
closure, so there is a circular reference.
I don't see a way to overcome this - consider the following code:
def outer():
def inner():
inner()
if random.random() > .5:
return inner
How is the GC/refcounting to know if it can create a reference or not?
Diez
More information about the Python-list
mailing list