Reference Counts

Heiko Wundram me+python at modelnine.org
Thu May 18 08:43:54 CEST 2006


Am Donnerstag 18 Mai 2006 08:28 schrieb raghu:
> #!/usr/bin/python
>
> import sys
> global a
>
> print "Total Reference count at the start =",sys.gettotalrefcount()
> a=1
> print "a ref count =",sys.getrefcount(a)
> b=a
> print "a ref count =",sys.getrefcount(a)
>
> del a
> del b
>
> print "Total Reference count at the end =",sys.gettotalrefcount()
> ...
> Total Reference count at the start = 16538
> a ref count = 49
> a ref count = 50
> Total Reference count at the end = 16540
> [6416 refs]
>
> There are a few questions that I am having on this.
>
> (1) Why should 'a' reference count be 49 before I even made an
> assignment ?

Because "1" is a special integer. Small integers (-1..100, but this depends on 
the Python version) are interned, similar to strings, so there are already 
references to the integer object before you assign it to "a" (at least one; 1 
is such a "magic" constant that you can guess that there are already other 
references to it in other places of the stdlib, which has loaded when your 
script runs, so it's not hard to imagine that 1 already has 48 references 
outside of your program).

> (2) The Total Reference count at the end has increased by 2 . Why ? Am
> I leaking memory ?

No. I'd guess that the names "a" and "b" were interned as strings (as they are 
used as dict lookup keys in the globals() dict), and you have one reference 
to each interned object.

> (3) I have read somewhere that an increase in sys.gettotalrefcount() is
> indicative of a memory leak ? Aint that correct ?

Yes. It is correct if consecutive runs of your algorithm always yield a higher 
sys.gettotalrefcount() for each run. In this case (where you run 
your "algorithm" only once), it isn't. It just shows you some of the innards 
of the Python runtime machinery.

Execute the following script to see the result of a memory leak:

>>>
import sys

x = {}
i = 0
def test():
    global x, i
    x[i] = "test"
    i += 1
    # Forget to clean up x... LEAK a reference to "test"!

for j in xrange(10000):
    print "Before", j, ":", sys.gettotalrefcount()
    test()
    print "After", j, ":", sys.gettotalrefcount()
>>>

And, the following (slightly altered) program doesn't exhibit this memory 
leak:

>>>
import sys

x = {}
i = 0
def test():
    global x, i
    x[i] = "test"
    i += 1
    del x[i-1] # Properly clean up x.

for j in xrange(10000):
    print "Before", j, ":", sys.gettotalrefcount()
    test()
    print "After", j, ":", sys.gettotalrefcount()
>>>

I don't have a debug build of Python at hand, so I can't run them now. But, if 
you're interested in the results, you'll certainly do that yourself. ;-)

--- Heiko.



More information about the Python-list mailing list