Index: Python/sysmodule.c =================================================================== --- Python/sysmodule.c (revision 63156) +++ Python/sysmodule.c (working copy) @@ -790,32 +790,12 @@ Clear the internal type lookup cache."); -static PyObject * -sys_compact_freelists(PyObject* self, PyObject* args) -{ - size_t isum, ibc, ibf; - size_t fsum, fbc, fbf; - - PyInt_CompactFreeList(&ibc, &ibf, &isum); - PyFloat_CompactFreeList(&fbc, &fbf, &fsum); - - return Py_BuildValue("(kkk)(kkk)", isum, ibc, ibf, - fsum, fbc, fbf); - -} - -PyDoc_STRVAR(sys_compact_freelists__doc__, -"_compact_freelists() -> ((remaing_objects, total_blocks, freed_blocks), ...)\n\ -Compact the free lists of ints and floats."); - static PyMethodDef sys_methods[] = { /* Might as well keep this in alphabetic order */ {"callstats", (PyCFunction)PyEval_GetCallStats, METH_NOARGS, callstats_doc}, {"_clear_type_cache", sys_clear_type_cache, METH_NOARGS, sys_clear_type_cache__doc__}, - {"_compact_freelists", sys_compact_freelists, METH_NOARGS, - sys_compact_freelists__doc__}, {"_current_frames", sys_current_frames, METH_NOARGS, current_frames_doc}, {"displayhook", sys_displayhook, METH_O, displayhook_doc}, Index: Include/intobject.h =================================================================== --- Include/intobject.h (revision 63156) +++ Include/intobject.h (working copy) @@ -60,7 +60,7 @@ PyAPI_FUNC(long) PyOS_strtol(char *, char **, int); /* free list api */ -PyAPI_FUNC(void) PyInt_CompactFreeList(size_t *, size_t *, size_t *); +PyAPI_FUNC(int) PyInt_ClearFreeList(void); /* Convert an integer to the given base. Returns a string. If base is 2, 8 or 16, add the proper prefix '0b', '0o' or '0x'. Index: Include/floatobject.h =================================================================== --- Include/floatobject.h (revision 63156) +++ Include/floatobject.h (working copy) @@ -113,7 +113,7 @@ PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le); /* free list api */ -PyAPI_FUNC(void) PyFloat_CompactFreeList(size_t *, size_t *, size_t *); +PyAPI_FUNC(int) PyFloat_ClearFreeList(void); #ifdef __cplusplus } Index: Objects/intobject.c =================================================================== --- Objects/intobject.c (revision 63156) +++ Objects/intobject.c (working copy) @@ -1301,35 +1301,33 @@ return 1; } -void -PyInt_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum) +int +PyInt_ClearFreeList(void) { PyIntObject *p; PyIntBlock *list, *next; - unsigned int ctr; - size_t bc = 0, bf = 0; /* block count, number of freed blocks */ - size_t isum = 0; /* total unfreed ints */ - int irem; /* remaining unfreed ints per block */ + int i; + int u; /* remaining unfreed ints per block */ + int freelist_size = 0; list = block_list; block_list = NULL; free_list = NULL; while (list != NULL) { - bc++; - irem = 0; - for (ctr = 0, p = &list->objects[0]; - ctr < N_INTOBJECTS; - ctr++, p++) { + u = 0; + for (i = 0, p = &list->objects[0]; + i < N_INTOBJECTS; + i++, p++) { if (PyInt_CheckExact(p) && p->ob_refcnt != 0) - irem++; + u++; } next = list->next; - if (irem) { + if (u) { list->next = block_list; block_list = list; - for (ctr = 0, p = &list->objects[0]; - ctr < N_INTOBJECTS; - ctr++, p++) { + for (i = 0, p = &list->objects[0]; + i < N_INTOBJECTS; + i++, p++) { if (!PyInt_CheckExact(p) || p->ob_refcnt == 0) { Py_TYPE(p) = (struct _typeobject *) @@ -1350,15 +1348,12 @@ } else { PyMem_FREE(list); - bf++; } - isum += irem; + freelist_size += u; list = next; } - *pbc = bc; - *pbf = bf; - *bsum = isum; + return freelist_size; } void @@ -1366,12 +1361,10 @@ { PyIntObject *p; PyIntBlock *list; - unsigned int ctr; - size_t bc, bf; /* block count, number of freed blocks */ - size_t isum; /* total unfreed ints per block */ + int i; + int u; /* total unfreed ints per block */ #if NSMALLNEGINTS + NSMALLPOSINTS > 0 - int i; PyIntObject **q; i = NSMALLNEGINTS + NSMALLPOSINTS; @@ -1381,27 +1374,24 @@ *q++ = NULL; } #endif - PyInt_CompactFreeList(&bc, &bf, &isum); + u = PyInt_ClearFreeList(); if (!Py_VerboseFlag) return; fprintf(stderr, "# cleanup ints"); - if (!isum) { + if (!u) { fprintf(stderr, "\n"); } else { fprintf(stderr, - ": %" PY_FORMAT_SIZE_T "d unfreed int%s in %" - PY_FORMAT_SIZE_T "d out of %" - PY_FORMAT_SIZE_T "d block%s\n", - isum, isum == 1 ? "" : "s", - bc - bf, bc, bc == 1 ? "" : "s"); + ": %d unfreed int%s\n", + u, u == 1 ? "" : "s"); } if (Py_VerboseFlag > 1) { list = block_list; while (list != NULL) { - for (ctr = 0, p = &list->objects[0]; - ctr < N_INTOBJECTS; - ctr++, p++) { + for (i = 0, p = &list->objects[0]; + i < N_INTOBJECTS; + i++, p++) { if (PyInt_CheckExact(p) && p->ob_refcnt != 0) /* XXX(twouters) cast refcount to long until %zd is universally Index: Objects/floatobject.c =================================================================== --- Objects/floatobject.c (revision 63156) +++ Objects/floatobject.c (working copy) @@ -1612,30 +1612,28 @@ PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc); } -void -PyFloat_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum) +int +PyFloat_ClearFreeList(void) { PyFloatObject *p; PyFloatBlock *list, *next; - unsigned i; - size_t bc = 0, bf = 0; /* block count, number of freed blocks */ - size_t fsum = 0; /* total unfreed ints */ - int frem; /* remaining unfreed ints per block */ + int i; + int u; /* remaining unfreed ints per block */ + int freelist_size = 0; list = block_list; block_list = NULL; free_list = NULL; while (list != NULL) { - bc++; - frem = 0; + u = 0; for (i = 0, p = &list->objects[0]; i < N_FLOATOBJECTS; i++, p++) { if (PyFloat_CheckExact(p) && Py_REFCNT(p) != 0) - frem++; + u++; } next = list->next; - if (frem) { + if (u) { list->next = block_list; block_list = list; for (i = 0, p = &list->objects[0]; @@ -1650,15 +1648,12 @@ } } else { - PyMem_FREE(list); /* XXX PyObject_FREE ??? */ - bf++; + PyMem_FREE(list); } - fsum += frem; + freelist_size += u; list = next; } - *pbc = bc; - *pbf = bf; - *bsum = fsum; + return freelist_size; } void @@ -1666,25 +1661,21 @@ { PyFloatObject *p; PyFloatBlock *list; - unsigned i; - size_t bc, bf; /* block count, number of freed blocks */ - size_t fsum; /* total unfreed floats per block */ + int i; + int u; /* total unfreed floats per block */ - PyFloat_CompactFreeList(&bc, &bf, &fsum); + u = PyFloat_ClearFreeList(); if (!Py_VerboseFlag) return; fprintf(stderr, "# cleanup floats"); - if (!fsum) { + if (!u) { fprintf(stderr, "\n"); } else { fprintf(stderr, - ": %" PY_FORMAT_SIZE_T "d unfreed float%s in %" - PY_FORMAT_SIZE_T "d out of %" - PY_FORMAT_SIZE_T "d block%s\n", - fsum, fsum == 1 ? "" : "s", - bc - bf, bc, bc == 1 ? "" : "s"); + ": %d unfreed float%s\n", + u, u == 1 ? "" : "s"); } if (Py_VerboseFlag > 1) { list = block_list; Index: Doc/c-api/float.rst =================================================================== --- Doc/c-api/float.rst (revision 63156) +++ Doc/c-api/float.rst (working copy) @@ -86,10 +86,9 @@ .. versionadded:: 2.6 -.. cfunction:: void PyFloat_CompactFreeList(size_t *bc, size_t *bf, size_t *sum) +.. cfunction:: int PyFloat_ClearFreeList(void) - Compact the float free list. *bc* is the number of allocated blocks before - blocks are freed, *bf* is the number of freed blocks and *sum* is the number - of remaining objects in the blocks. + Clear the float free list. Return the number of items that could not + be freed. .. versionadded:: 2.6 Index: Doc/c-api/int.rst =================================================================== --- Doc/c-api/int.rst (revision 63156) +++ Doc/c-api/int.rst (working copy) @@ -122,10 +122,9 @@ (:const:`LONG_MAX`, as defined in the system header files). -.. cfunction:: void PyInt_CompactFreeList(size_t *bc, size_t *bf, size_t *sum) +.. cfunction:: int PyInt_ClearFreeList(void) - Compact the integer free list. *bc* is the number of allocated blocks before - blocks are freed, *bf* is the number of freed blocks and *sum* is the number - of remaining objects in the blocks. + Clear the integer free list. Return the number of items that could not + be freed. .. versionadded:: 2.6 Index: Doc/library/gc.rst =================================================================== --- Doc/library/gc.rst (revision 63156) +++ Doc/library/gc.rst (working copy) @@ -47,7 +47,13 @@ .. versionchanged:: 2.5 The optional *generation* argument was added. + .. versionchanged:: 2.6 + The free lists maintained for a number of builtin types are cleared + whenever a full collection or collection of the highest generation (2) + is run. Not all items in some free lists may be freed due to the + particular implementation, in particular :class:`int` and :class:`float`. + .. function:: set_debug(flags) Set the garbage collection debugging flags. Debugging information will be Index: Doc/library/sys.rst =================================================================== --- Doc/library/sys.rst (revision 63156) +++ Doc/library/sys.rst (working copy) @@ -58,22 +58,6 @@ A string containing the copyright pertaining to the Python interpreter. -.. function:: _compact_freelists() - - Compact the free lists of integers and floats by deallocating unused blocks. - It can reduce the memory usage of the Python process several tenth of - thousands of integers or floats have been allocated at once. - - The return value is a tuple of tuples each containing three elements, - amount of used objects, total block count before the blocks are deallocated - and amount of freed blocks. The first tuple refers to ints, the second to - floats. - - This function should be used for specialized purposes only. - - .. versionadded:: 2.6 - - .. function:: _clear_type_cache() Clear the internal type cache. The type cache is used to speed up attribute Index: Lib/test/test_sys.py =================================================================== --- Lib/test/test_sys.py (revision 63156) +++ Lib/test/test_sys.py (working copy) @@ -366,25 +366,6 @@ def test_clear_type_cache(self): sys._clear_type_cache() - def test_compact_freelists(self): - sys._compact_freelists() - r = sys._compact_freelists() -## # freed blocks shouldn't change -## self.assertEqual(r[0][2], 0) -## self.assertEqual(r[1][2], 0) -## # fill freelists -## ints = list(range(10000)) -## floats = [float(i) for i in ints] -## del ints -## del floats -## # should free more than 200 blocks each -## r = sys._compact_freelists() -## self.assert_(r[0][1] > 100, r[0][1]) -## self.assert_(r[1][2] > 100, r[1][1]) -## -## self.assert_(r[0][2] > 100, r[0][2]) -## self.assert_(r[1][2] > 100, r[1][2]) - def test_main(): test.test_support.run_unittest(SysModuleTest) Index: Modules/gcmodule.c =================================================================== --- Modules/gcmodule.c (revision 63156) +++ Modules/gcmodule.c (working copy) @@ -736,6 +736,8 @@ (void)PyCFunction_ClearFreeList(); (void)PyTuple_ClearFreeList(); (void)PyUnicode_ClearFreeList(); + (void)PyInt_ClearFreeList(); + (void)PyFloat_ClearFreeList(); } /* This is the main function. Read this to understand how the