[Python-bugs-list] [ python-Bugs-485139 ] mem leak in interpreter from syntax err
noreply@sourceforge.net
noreply@sourceforge.net
Sat, 08 Dec 2001 15:21:17 -0800
Bugs item #485139, was opened at 2001-11-24 10:45
You can respond by visiting:
http://sourceforge.net/tracker/?func=detail&atid=105470&aid=485139&group_id=5470
Category: Python Interpreter Core
Group: Python 2.2
Status: Open
Resolution: Wont Fix
Priority: 5
Submitted By: Neal Norwitz (nnorwitz)
Assigned to: Tim Peters (tim_one)
Summary: mem leak in interpreter from syntax err
Initial Comment:
when a syntax error occurs in the interpreter, the
interpreter leaks
see the attached file for more info
----------------------------------------------------------------------
>Comment By: Tim Peters (tim_one)
Date: 2001-12-08 15:21
Message:
Logged In: YES
user_id=31435
Don't ask how I found this <wink>: in the def and class
examples, we're "leaking" references to the integer 1(!).
C:\Code\python\PCbuild>python_d
Adding parser accelerators ...
Done.
Python 2.2b2+ (#26, Dec 8 2001, 17:33:44) [MSC 32 bit
(Intel)] on win32
Type "help", "copyright", "credits" or "license" for more
information.
>>> def g(): # return the current refcount on 1
... import sys
... return sys.getrefcount(1)
...
[7037 refs]
>>> g() # it's 38 now
38
[7040 refs]
>>> g() # and it's still 38
38
[7040 refs]
>>> def f(): pass # do 3 function defs, and ...
...
[7057 refs]
>>> def f(): pass
...
[7058 refs]
>>> def f(): pass
...
[7059 refs]
>>> g() # ... the refcount on 1 goes up by 3
41
[7060 refs]
>>> class C: pass # then do 5 class defs, and ...
...
[7070 refs]
>>> class C: pass
...
[7071 refs]
>>> class C: pass
...
[7072 refs]
>>> class C: pass
...
[7073 refs]
>>> class C: pass
...
[7074 refs]
>>> g() # ... the refcount on 1 goes up by 5
46
[7075 refs]
>>>
Similarly for, e.g., entering "lambda:42" over and over. I
don't know *why* we're leaking refs to 1 -- it's bizarre.
----------------------------------------------------------------------
Comment By: Tim Peters (tim_one)
Date: 2001-12-08 14:32
Message:
Logged In: YES
user_id=31435
The difference between _Py_RefTotal and the sum of the
refcounts of the objects in refchain is at least partly
accounted for by that static type objects don't appear in
refchain. The two get out of synch already by the time
_Py_RefTotal reaches 4, due to the static PyBaseObject_Type
showing up in a tuple of base classes (thus adding a count
to _Py_RefTotal that's not seen when traversing refchain).
----------------------------------------------------------------------
Comment By: Tim Peters (tim_one)
Date: 2001-12-07 21:51
Message:
Logged In: YES
user_id=31435
Well, this just gets more mysterious the longer I stare at
it. I added a routine to compute the sum of all the
refcounts in the objects in the refchain, and fiddled
PyRun_InteractiveLoopFlags to print that sum after printing
_Py_RefTotal. That's the first mystery:
C:\Code\python\PCbuild>python_d
Adding parser accelerators ...
Done.
Python 2.2b2+ (#26, Dec 7 2001, 19:25:48) [MSC 32 bit
(Intel)] on win32
Type "help", "copyright", "credits" or "license" for more
information.
>>>
[7004 refs] # _Py_RefTotal
[6540 sum] # sum of ob_refcnt across refchain objs
That is, right off the bat, _Py_RefTotal is 536 larger than
the sum of all refcounts in all known objects. I hoped
they'd be equal.
At least these stay in synch across lots of input
expressions:
>>> 1
1
[7006 refs]
[6542 sum]
Both went up by 2 there.
>>> []
[]
[7011 refs]
[6547 sum]
And both up by 5.
>>> ()
()
[7011 refs]
[6547 sum]
No change.
>>> {}
{}
[7011 refs]
[6547 sum]
No change.
>>> 2.3
2.2999999999999998
[7011 refs]
[6547 sum]
No change. Now comes another Mystery:
>>> def f(): pass
...
[7028 refs]
[6562 sum]
That is, _Py_RefTotal went up by 17, but the sum of all
refcounts only went up by 15. What's up with that?
Then both "leak" 1 for each repetition of a function defn:
>>> def f(): pass
...
[7029 refs]
[6563 sum]
>>> def f(): pass
...
[7030 refs]
[6564 sum]
>>> def f(): pass
...
[7031 refs]
[6565 sum]
>>>
That makes three mysteries. There's no other evidence of
an actual leak, though! In particular,
>>> import sys
[7036 refs]
[6570 sum]
>>> for i in range(10):
... def f(): pass
... print sys.gettotalrefcount()
...
7075
7075
7075
7075
7075
7075
7075
7075
7075
7075
[7037 refs]
[6571 sum]
>>>
That is, _PyRef_Total is *not* going up by 1 on each "def f
(): pass" if the def stmt is inside a loop.
Reducing the priority since this is such a pit.
----------------------------------------------------------------------
Comment By: Tim Peters (tim_one)
Date: 2001-12-07 09:13
Message:
Logged In: YES
user_id=31435
Reopened and assigned to me. I don't care about a leak on
an uncaught syntax error, but something Neal said reminded
me of a problem that's repeatedly wasted my time: "enter
something at a debug-mode interactive prompt repeatedly"
often exhibits "and lose a refcount each time" behavior.
Like so:
>>> 1
1
[7026 refs]
>>> class C: pass
...
[7036 refs]
>>> class C: pass
...
[7037 refs]
>>> class C: pass
...
[7038 refs]
>>> class C: pass
...
[7039 refs]
>>>
Several times this has fooled me into looking for leaks
that don't exist.
>>> def f(): pass
...
[7056 refs]
>>> def f(): pass
...
[7057 refs]
>>> def f(): pass
...
[7058 refs]
>>>
----------------------------------------------------------------------
Comment By: Guido van Rossum (gvanrossum)
Date: 2001-12-07 08:46
Message:
Logged In: YES
user_id=6380
Neal writes:
---
I tried:
for i in range(1000):
try:
import t2
except SyntaxError:
print
But that doesn't leak. I think the reason it doesn't leak
is because
of the try/except. I opened the interpreter and
interactively
created syntax errors (=<return>, =<return>, ...) and it
leaked
for each error, not just once 874 bytes, instead of 38 for
1.
If there is a way to raise a syntax error without exitting
the interpreterr
I think it could blow up faster.
-----
My comment: if it only leaks when you don't catch it, that
doesn't bother me much, since that's the end of the process.
:-) So I'm closing this.
----------------------------------------------------------------------
Comment By: Guido van Rossum (gvanrossum)
Date: 2001-12-06 19:11
Message:
Logged In: YES
user_id=6380
Neil, can you provide more evidence? I can't see this leak
in a loop, like this:
| while 1:
| try: compile("/", "", "exec")
| except SyntaxError: pass
----------------------------------------------------------------------
Comment By: Tim Peters (tim_one)
Date: 2001-11-27 12:05
Message:
Logged In: YES
user_id=31435
Assigned to Barry.
----------------------------------------------------------------------
You can respond by visiting:
http://sourceforge.net/tracker/?func=detail&atid=105470&aid=485139&group_id=5470