[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

Why this ref leak?

Gerhard Häring

2/27/2008 12:19:00 PM

import sys

def foo():
class C(object):
pass

foo()
print ">>", sys.gettotalrefcount()
foo()
print ">>", sys.gettotalrefcount()
foo()
print ">>", sys.gettotalrefcount()

>> 21366
>> 21387
>> 21408
[9779 refs]

Both Python 2.4 and 2.5 don't clean up properly here. Why is this?
Aren't classes supposed to be garbage-collected?

-- Gerhard
7 Answers

Bjoern Schliessmann

2/27/2008 12:49:00 PM

0

Gerhard Häring wrote:

> Both Python 2.4 and 2.5 don't clean up properly here. Why is this?
> Aren't classes supposed to be garbage-collected?

Yes, but not neccessarily immediately.

BTW, where is your method sys.gettotalrefcount supposed to come
from? My CPython doesn't have it.

Regards,


Björn

--
BOFH excuse #219:

Recursivity. Call back if it happens again.

Peter Otten

2/27/2008 12:51:00 PM

0

Gerhard Häring wrote:

> import sys
>
> def foo():
> class C(object):
> pass
>
> foo()
> print ">>", sys.gettotalrefcount()
> foo()
> print ">>", sys.gettotalrefcount()
> foo()
> print ">>", sys.gettotalrefcount()
>
> >> 21366
> >> 21387
> >> 21408
> [9779 refs]
>
> Both Python 2.4 and 2.5 don't clean up properly here. Why is this?
> Aren't classes supposed to be garbage-collected?

The reference keeping the classes alive is probably object.__subclasses__():

>>> class A(object): pass
....
>>> sum(1 for c in object.__subclasses__() if c.__name__ == "A")
1
>>> class A(object): pass
....
>>> sum(1 for c in object.__subclasses__() if c.__name__ == "A")
2

Peter

Thomas Heller

2/27/2008 1:12:00 PM

0

Gerhard Häring schrieb:
> import sys
>
> def foo():
> class C(object):
> pass
>
> foo()
> print ">>", sys.gettotalrefcount()
> foo()
> print ">>", sys.gettotalrefcount()
> foo()
> print ">>", sys.gettotalrefcount()
>
> >> 21366
> >> 21387
> >> 21408
> [9779 refs]
>
> Both Python 2.4 and 2.5 don't clean up properly here. Why is this?
> Aren't classes supposed to be garbage-collected?
>
> -- Gerhard

Replace "foo()" with "foo(); gc.collect()" and the refcounts are stable.
Tested the python 2.6 from trunk.

Thomas

Peter Otten

2/27/2008 1:13:00 PM

0

Peter Otten wrote:

>> Both Python 2.4 and 2.5 don't clean up properly here. Why is this?
>> Aren't classes supposed to be garbage-collected?
>
> The reference keeping the classes alive is probably
> object.__subclasses__():
>
>>>> class A(object): pass
> ...
>>>> sum(1 for c in object.__subclasses__() if c.__name__ == "A")
> 1
>>>> class A(object): pass
> ...
>>>> sum(1 for c in object.__subclasses__() if c.__name__ == "A")
> 2

Oops, wrong guess:

>>> import gc
>>> gc.collect()
6
>>> sum(1 for c in object.__subclasses__() if c.__name__ == "A")
1

Peter

Peter Otten

2/27/2008 1:18:00 PM

0

Bjoern Schliessmann wrote:

> BTW, where is your method sys.gettotalrefcount supposed to come
> from? My CPython doesn't have it.

It's in the debug build only.

Peter

Bjoern Schliessmann

2/27/2008 2:25:00 PM

0

Peter Otten wrote:
> Bjoern Schliessmann wrote:

>> BTW, where is your method sys.gettotalrefcount supposed to come
>> from? My CPython doesn't have it.
>
> It's in the debug build only.

Makes sense; thank you.

Regards,


Björn

--
BOFH excuse #292:

We ran out of dial tone and we're and waiting for the phone company
to deliver another bottle.

Duncan Booth

2/27/2008 2:25:00 PM

0

Peter Otten <__peter__@web.de> wrote:

> Peter Otten wrote:
>
>>> Both Python 2.4 and 2.5 don't clean up properly here. Why is this?
>>> Aren't classes supposed to be garbage-collected?
>>
>> The reference keeping the classes alive is probably
>> object.__subclasses__():
>>
>>>>> class A(object): pass
>> ...
>>>>> sum(1 for c in object.__subclasses__() if c.__name__ == "A")
>> 1
>>>>> class A(object): pass
>> ...
>>>>> sum(1 for c in object.__subclasses__() if c.__name__ == "A")
>> 2
>
> Oops, wrong guess:
>
>>>> import gc
>>>> gc.collect()
> 6
>>>> sum(1 for c in object.__subclasses__() if c.__name__ == "A")
> 1
>
The list of subclasses is stored using weak references: that's why you have
to call a method to create a real list. What actually stops the class just
vapourising is its __mro__ attribute which creates a cycle, but the garbage
collector clears that up as you saw.