Implemented Martin's suggestion to clear the free lists during the garbage collection of the highest generation.
diff --git a/Objects/classobject.c b/Objects/classobject.c
index 759027b..6c77153 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -2626,9 +2626,11 @@
/* Clear out the free list */
-void
-PyMethod_Fini(void)
+int
+PyMethod_ClearFreeList(void)
{
+ int freelist_size = numfree;
+
while (free_list) {
PyMethodObject *im = free_list;
free_list = (PyMethodObject *)(im->im_self);
@@ -2636,4 +2638,11 @@
numfree--;
}
assert(numfree == 0);
+ return freelist_size;
+}
+
+void
+PyMethod_Fini(void)
+{
+ (void)PyMethod_ClearFreeList();
}
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index df9c2e0..025431e 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -889,10 +889,11 @@
}
/* Clear out the free list */
-
-void
-PyFrame_Fini(void)
+int
+PyFrame_ClearFreeList(void)
{
+ int freelist_size = numfree;
+
while (free_list != NULL) {
PyFrameObject *f = free_list;
free_list = free_list->f_back;
@@ -900,6 +901,13 @@
--numfree;
}
assert(numfree == 0);
+ return freelist_size;
+}
+
+void
+PyFrame_Fini(void)
+{
+ (void)PyFrame_ClearFreeList();
Py_XDECREF(builtin_object);
builtin_object = NULL;
}
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index 0d9cf1c..d661c47 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -353,9 +353,11 @@
/* Clear out the free list */
-void
-PyCFunction_Fini(void)
+int
+PyCFunction_ClearFreeList(void)
{
+ int freelist_size = numfree;
+
while (free_list) {
PyCFunctionObject *v = free_list;
free_list = (PyCFunctionObject *)(v->m_self);
@@ -363,6 +365,13 @@
numfree--;
}
assert(numfree == 0);
+ return freelist_size;
+}
+
+void
+PyCFunction_Fini(void)
+{
+ (void)PyCFunction_ClearFreeList();
}
/* PyCFunction_New() is now just a macro that calls PyCFunction_NewEx(),
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index dfd2a16..e9cb3ef 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -832,19 +832,18 @@
return 0;
}
-void
-PyTuple_Fini(void)
+int
+PyTuple_ClearFreeList(void)
{
+ int freelist_size = 0;
#if PyTuple_MAXSAVESIZE > 0
int i;
-
- Py_XDECREF(free_list[0]);
- free_list[0] = NULL;
-
for (i = 1; i < PyTuple_MAXSAVESIZE; i++) {
PyTupleObject *p, *q;
p = free_list[i];
+ freelist_size += numfree[i];
free_list[i] = NULL;
+ numfree[i] = 0;
while (p) {
q = p;
p = (PyTupleObject *)(p->ob_item[0]);
@@ -852,6 +851,20 @@
}
}
#endif
+ return freelist_size;
+}
+
+void
+PyTuple_Fini(void)
+{
+#if PyTuple_MAXSAVESIZE > 0
+ /* empty tuples are used all over the place and applications may
+ * rely on the fact that an empty tuple is a singleton. */
+ Py_XDECREF(free_list[0]);
+ free_list[0] = NULL;
+
+ (void)PyTuple_ClearFreeList();
+#endif
}
/*********************** Tuple Iterator **************************/
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 74b4796..3e15f53 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -8853,10 +8853,29 @@
/* Finalize the Unicode implementation */
+int
+PyUnicode_ClearFreeList(void)
+{
+ int freelist_size = numfree;
+ PyUnicodeObject *u;
+
+ for (u = free_list; u != NULL;) {
+ PyUnicodeObject *v = u;
+ u = *(PyUnicodeObject **)u;
+ if (v->str)
+ PyMem_DEL(v->str);
+ Py_XDECREF(v->defenc);
+ PyObject_Del(v);
+ numfree--;
+ }
+ free_list = NULL;
+ assert(numfree == 0);
+ return freelist_size;
+}
+
void
_PyUnicode_Fini(void)
{
- PyUnicodeObject *u;
int i;
Py_XDECREF(unicode_empty);
@@ -8868,17 +8887,7 @@
unicode_latin1[i] = NULL;
}
}
-
- for (u = free_list; u != NULL;) {
- PyUnicodeObject *v = u;
- u = *(PyUnicodeObject **)u;
- if (v->str)
- PyMem_DEL(v->str);
- Py_XDECREF(v->defenc);
- PyObject_Del(v);
- }
- free_list = NULL;
- numfree = 0;
+ (void)PyUnicode_ClearFreeList();
}
#ifdef __cplusplus