473,378 Members | 1,393 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,378 software developers and data experts.

Reference Counts

Hi All,

I am a new user of Python and am having a bit of problem understanding
the Reference counting and memory leakage issues.

Requesting help from experienced users....

I wrote the following simple program.
#!/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()
I executed it. I am seeing the following.

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 ?
(2) The Total Reference count at the end has increased by 2 . Why ? Am
I leaking memory ?
(3) I have read somewhere that an increase in sys.gettotalrefcount() is
indicative of a memory leak ? Aint that correct ?

Thanks for the help.

Bye,
raghavan V

May 18 '06 #1
5 1417
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.
May 18 '06 #2
Heiko,

Thanks for the explanation. I understood the idea of 1 being interned.
Also I understood the globals vars having a reference in the internal
dict.

I ran the "leaky" version of the program and yes...it showed a
progressively increasing totalrefcount as below.
Before 0 : 16579
After 0 : 16581
Before 1 : 16581
After 1 : 16583
Before 2 : 16583
After 2 : 16585
Before 3 : 16585
After 3 : 16587
Before 4 : 16587
After 4 : 16589
Before 5 : 16589
After 5 : 16591
Before 6 : 16591
After 6 : 16593
Before 7 : 16593
After 7 : 16595
Before 8 : 16595
After 8 : 16597
Before 9 : 16597
After 9 : 16599
Before 10 : 16599
After 10 : 16601
Before 11 : 16601
After 11 : 16603
Before 12 : 16603
After 12 : 16605
Before 13 : 16605
After 13 : 16607
Before 14 : 16607
After 14 : 16609
Before 15 : 16609

However, the 'non-leaky' one showed a funny trend ...it kept increasing
the totalrefcount for five iterations (see 1 thru 5) and then dropped
down by 5 ( See Before 5 : 16584
After 5 : 16580 ) suddenly and again increase as shown below. However,
at the time when the script finsished execution, we were not too far
from the starting totalrefcount (16584 from 16579),
Before 0 : 16579
After 0 : 16580
Before 1 : 16580
After 1 : 16581
Before 2 : 16581
After 2 : 16582
Before 3 : 16582
After 3 : 16583
Before 4 : 16583
After 4 : 16584
Before 5 : 16584
After 5 : 16580
Before 6 : 16580
After 6 : 16581
Before 7 : 16581
After 7 : 16582
Before 8 : 16582
After 8 : 16583
Before 9 : 16583
After 9 : 16584
Before 10 : 16584
After 10 : 16580
Before 11 : 16580
After 11 : 16581
Before 12 : 16581
After 12 : 16582
Before 13 : 16582
After 13 : 16583
Before 14 : 16583
After 14 : 16584
Before 15 : 16584

What is the Mystery behind the increase and the subsequent drop ?

Thanks.

Raghavan V

May 18 '06 #3
Am Donnerstag 18 Mai 2006 09:33 schrieb raghu:
However, the 'non-leaky' one showed a funny trend ...it kept increasing
the totalrefcount for five iterations (see 1 thru 5) and then dropped
down by 5 ( See Before 5 : 16584
After 5 : 16580 ) suddenly and again increase as shown below. However,
at the time when the script finsished execution, we were not too far
from the starting totalrefcount (16584 from 16579),


The cyclic garbage collector isn't run after every byte-code instruction, but
only after several have executed (because of performance issues). That's why
you see an increase in reference counts, until the interpreter calls the
garbage collector, which frees the object cycles, and so forth. I don't
exactly know what the "magic constant" (i.E. number of byte-code instructions
between subsequent runs of the garbage collector) is, but I presume it's
somewhere in the order of 100 bytecode instructions.

Why you need the cyclic gc to clean up the data structures my sample creates
is beyond be, but I'd guess it has something to do with the internal
structure of dicts.

Anyway, you can easily test this hypothesis by calling

gc.collect()

explicitly in the main loop after test() has run (remember to import
gc... ;-)). This forces a run of the cyclic gc. If funny pattern still
remains I wouldn't know of any other explanation... ;-) But, as long as
references aren't being leaked (you don't see the drop in references after
every x instructions), there's nothing to worry about.

--- Heiko.
May 18 '06 #4
Hmm...

I tried the gc.collect(). It aint helping. The reference count still
keeps growing till 5 after it which it drops. As you said, it is not
gonna hurt right away.

The only downside in that mysterious up and down thingie is that , we
could get to a wrong conclusion about a leak, if we ran the algo for
say 3 times. Right ?

Thanks Heiko for all the help. And in case, you get to decode the
mystery behind the increase before the decrease ..kindly let me know.

Bye,
Raghavan V

May 19 '06 #5
[raghu, on Heiko Wundram's test program:

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()
]
Hmm...

I tried the gc.collect(). It aint helping. The reference count still
keeps growing till 5 after it which it drops. As you said, it is not
gonna hurt right away.

The only downside in that mysterious up and down thingie is that , we
could get to a wrong conclusion about a leak, if we ran the algo for
say 3 times. Right ?

Thanks Heiko for all the help. And in case, you get to decode the
mystery behind the increase before the decrease ..kindly let me know.


It has nothing to do with cyclic gc. It has to do with this:

del x[i-1] # Properly clean up x.

When you remove a dictionary key, under the covers the dictionary slot
that contained the deleted <key, value> pair has its value portion set
to a special "dummy" object. This is invisible from the Python level
(there's no way you can get at this object), but the dummy object is a
real Python object, and like all Python objects has a refcount. Each
time the dummy object gets used, its refcount is bumped, and that
shows up in gettotalrefcount(). From time to time the dict resizes,
and then the number of references to the dummy dict value changes
sharply.

Except in the upcoming 2.5 release. The refcount on the dummy dict
value (and the similar dummy set value) confuses people so much that
gettotalrefcount() has been changed in 2.5 to subtract the refcounts
on the dummy dict and set values. As a result, running under current
2.5 trunk Heiko's program is steady as a rock:

Before 0 : 25632
After 0 : 25632
Before 1 : 25632
After 1 : 25632
Before 2 : 25632
After 2 : 25632
Before 3 : 25632
After 3 : 25632
Before 4 : 25632
After 4 : 25632
Before 5 : 25632
After 5 : 25632
Before 6 : 25632
After 6 : 25632
Before 7 : 25632
After 7 : 25632
Before 8 : 25632
After 8 : 25632
Before 9 : 25632
After 9 : 25632
Before 10 : 25632
After 10 : 25632
....
May 19 '06 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
by: Eric | last post by:
Hi, After reading the JNI specs, it looks like no JNI call is available to retrieve the reference count for a specific Java Object (LocalRef or GlobalRef). I would like to able to retrieve...
6
by: Elbert Lev | last post by:
Please correct me if I'm wrong. Python (as I understand) uses reference counting to determine when to delete the object. As soon as the object goes out of the scope it is deleted. Python does...
6
by: Chris S. | last post by:
I'm trying to make a graphical editor and browser for Pickled files. One aspect I'm not sure about is how to detect multiple references to the same data. For instance, say I had the Pickled...
1
by: Tony Johansson | last post by:
Hello Experts! I reading a book called programming with design pattern revealed by Tomasz Muldner and here I read something that I don't understand completely. It says "A garbarage...
4
by: z_learning_tester | last post by:
I'm reading the MS press C# book and there seems to be a contradiction. Please tell me which one is correct, 1 or 2. Thanks! Jeff 1. First it gives the code below saying that it prints 0 then...
4
by: aaronfude | last post by:
Hi, Please consider the following class (it's not really my class, but it's a good example for my question): class Vector { int myN; double *myX; Vector(int n) : myN(n), myX(new double) { }...
1
by: DaveO. | last post by:
Hello, I'm calling a VB.NET web service, also from VB.NET, and I get the error " Object reference not set to an instance of an object" on the following line in Reference.vb, when it tries to...
1
by: oec.deepak | last post by:
Hi Cn any one telll me what is Reference counting in C++.
68
by: Jim Langston | last post by:
I remember there was a thread a while back that was talking about using the return value of a function as a reference where I had thought the reference would become invalidated because it was a...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.