summaryrefslogtreecommitdiffstats
path: root/Objects/frameobject.c
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2002-04-13 05:21:47 (GMT)
committerTim Peters <tim.peters@gmail.com>2002-04-13 05:21:47 (GMT)
commitb7ba7433126bff12dd638f11f831fa7bfd0bbf4a (patch)
tree951236002d7aa39e824b9d165e89dc8f0292e7b4 /Objects/frameobject.c
parent8b1c47bb8bf061d1842075a9e6edcc2736b3b236 (diff)
downloadcpython-b7ba7433126bff12dd638f11f831fa7bfd0bbf4a.zip
cpython-b7ba7433126bff12dd638f11f831fa7bfd0bbf4a.tar.gz
cpython-b7ba7433126bff12dd638f11f831fa7bfd0bbf4a.tar.bz2
SF bug 543148: Memory leak with stackframes + inspect.
Put a bound on the number of frameobjects that can live in the frameobject free_list. Am also backporting to 2.2. I don't intend to backport to 2.1 (too much work -- lots of cyclic structures leak there, and the GC API).
Diffstat (limited to 'Objects/frameobject.c')
-rw-r--r--Objects/frameobject.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 8e4c60f..165121d 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -56,9 +56,15 @@ static PyGetSetDef frame_getsetlist[] = {
After all, while a typical program may make millions of calls, a
call depth of more than 20 or 30 is probably already exceptional
unless the program contains run-away recursion. I hope.
+
+ Later, MAXFREELIST was added to bound the # of frames saved on
+ free_list. Else programs creating lots of cyclic trash involving
+ frames could provoke free_list into growing without bound.
*/
static PyFrameObject *free_list = NULL;
+static int numfree = 0; /* number of frames currently in free_list */
+#define MAXFREELIST 200 /* max value for numfree */
static void
frame_dealloc(PyFrameObject *f)
@@ -91,8 +97,13 @@ frame_dealloc(PyFrameObject *f)
Py_XDECREF(f->f_exc_type);
Py_XDECREF(f->f_exc_value);
Py_XDECREF(f->f_exc_traceback);
- f->f_back = free_list;
- free_list = f;
+ if (numfree < MAXFREELIST) {
+ ++numfree;
+ f->f_back = free_list;
+ free_list = f;
+ }
+ else
+ PyObject_GC_Del(f);
Py_TRASHCAN_SAFE_END(f)
}
@@ -245,6 +256,8 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
return NULL;
}
else {
+ assert(numfree > 0);
+ --numfree;
f = free_list;
free_list = free_list->f_back;
if (f->ob_size < extras) {
@@ -475,5 +488,7 @@ PyFrame_Fini(void)
PyFrameObject *f = free_list;
free_list = free_list->f_back;
PyObject_GC_Del(f);
+ --numfree;
}
+ assert(numfree == 0);
}