- Issue #2862: Make int and float freelist management consistent with other

freelists.  Changes their CompactFreeList apis into ClearFreeList apis and
  calls them via gc.collect().
This commit is contained in:
Gregory P. Smith 2008-07-06 03:35:58 +00:00
parent 17f2e4acb9
commit 2fe77060eb
11 changed files with 62 additions and 107 deletions

View File

@ -86,10 +86,9 @@ Floating Point Objects
.. versionadded:: 2.6 .. 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 Clear the float free list. Return the number of items that could not
blocks are freed, *bf* is the number of freed blocks and *sum* is the number be freed.
of remaining objects in the blocks.
.. versionadded:: 2.6 .. versionadded:: 2.6

View File

@ -122,10 +122,9 @@ Plain Integer Objects
(:const:`LONG_MAX`, as defined in the system header files). (: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 Clear the integer free list. Return the number of items that could not
blocks are freed, *bf* is the number of freed blocks and *sum* is the number be freed.
of remaining objects in the blocks.
.. versionadded:: 2.6 .. versionadded:: 2.6

View File

@ -47,6 +47,12 @@ The :mod:`gc` module provides the following functions:
.. versionchanged:: 2.5 .. versionchanged:: 2.5
The optional *generation* argument was added. 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) .. function:: set_debug(flags)

View File

@ -58,22 +58,6 @@ always available.
A string containing the copyright pertaining to the Python interpreter. 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() .. function:: _clear_type_cache()
Clear the internal type cache. The type cache is used to speed up attribute Clear the internal type cache. The type cache is used to speed up attribute

View File

@ -113,7 +113,7 @@ PyAPI_FUNC(double) _PyFloat_Unpack4(const unsigned char *p, int le);
PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le); PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le);
/* free list api */ /* free list api */
PyAPI_FUNC(void) PyFloat_CompactFreeList(size_t *, size_t *, size_t *); PyAPI_FUNC(int) PyFloat_ClearFreeList(void);
/* Format the object based on the format_spec, as defined in PEP 3101 /* Format the object based on the format_spec, as defined in PEP 3101
(Advanced String Formatting). */ (Advanced String Formatting). */

View File

@ -60,7 +60,7 @@ PyAPI_FUNC(unsigned long) PyOS_strtoul(char *, char **, int);
PyAPI_FUNC(long) PyOS_strtol(char *, char **, int); PyAPI_FUNC(long) PyOS_strtol(char *, char **, int);
/* free list api */ /* 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. /* 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'. If base is 2, 8 or 16, add the proper prefix '0b', '0o' or '0x'.

View File

@ -29,6 +29,10 @@ Core and Builtins
would not cause a syntax error. This was regression from 2.4 caused by the would not cause a syntax error. This was regression from 2.4 caused by the
switch to the new compiler. switch to the new compiler.
- Issue #2862: Make int and float freelist management consistent with other
freelists. Changes their CompactFreeList apis into ClearFreeList apis and
calls them via gc.collect().
Library Library
------- -------

View File

@ -736,6 +736,8 @@ clear_freelists(void)
(void)PyCFunction_ClearFreeList(); (void)PyCFunction_ClearFreeList();
(void)PyTuple_ClearFreeList(); (void)PyTuple_ClearFreeList();
(void)PyUnicode_ClearFreeList(); (void)PyUnicode_ClearFreeList();
(void)PyInt_ClearFreeList();
(void)PyFloat_ClearFreeList();
} }
/* This is the main function. Read this to understand how the /* This is the main function. Read this to understand how the

View File

@ -1608,30 +1608,28 @@ _PyFloat_Init(void)
PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc); PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc);
} }
void int
PyFloat_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum) PyFloat_ClearFreeList(void)
{ {
PyFloatObject *p; PyFloatObject *p;
PyFloatBlock *list, *next; PyFloatBlock *list, *next;
unsigned i; int i;
size_t bc = 0, bf = 0; /* block count, number of freed blocks */ int u; /* remaining unfreed ints per block */
size_t fsum = 0; /* total unfreed ints */ int freelist_size = 0;
int frem; /* remaining unfreed ints per block */
list = block_list; list = block_list;
block_list = NULL; block_list = NULL;
free_list = NULL; free_list = NULL;
while (list != NULL) { while (list != NULL) {
bc++; u = 0;
frem = 0;
for (i = 0, p = &list->objects[0]; for (i = 0, p = &list->objects[0];
i < N_FLOATOBJECTS; i < N_FLOATOBJECTS;
i++, p++) { i++, p++) {
if (PyFloat_CheckExact(p) && Py_REFCNT(p) != 0) if (PyFloat_CheckExact(p) && Py_REFCNT(p) != 0)
frem++; u++;
} }
next = list->next; next = list->next;
if (frem) { if (u) {
list->next = block_list; list->next = block_list;
block_list = list; block_list = list;
for (i = 0, p = &list->objects[0]; for (i = 0, p = &list->objects[0];
@ -1646,15 +1644,12 @@ PyFloat_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum)
} }
} }
else { else {
PyMem_FREE(list); /* XXX PyObject_FREE ??? */ PyMem_FREE(list);
bf++;
} }
fsum += frem; freelist_size += u;
list = next; list = next;
} }
*pbc = bc; return freelist_size;
*pbf = bf;
*bsum = fsum;
} }
void void
@ -1662,25 +1657,21 @@ PyFloat_Fini(void)
{ {
PyFloatObject *p; PyFloatObject *p;
PyFloatBlock *list; PyFloatBlock *list;
unsigned i; int i;
size_t bc, bf; /* block count, number of freed blocks */ int u; /* total unfreed floats per block */
size_t fsum; /* total unfreed floats per block */
PyFloat_CompactFreeList(&bc, &bf, &fsum); u = PyFloat_ClearFreeList();
if (!Py_VerboseFlag) if (!Py_VerboseFlag)
return; return;
fprintf(stderr, "# cleanup floats"); fprintf(stderr, "# cleanup floats");
if (!fsum) { if (!u) {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
else { else {
fprintf(stderr, fprintf(stderr,
": %" PY_FORMAT_SIZE_T "d unfreed float%s in %" ": %d unfreed float%s\n",
PY_FORMAT_SIZE_T "d out of %" u, u == 1 ? "" : "s");
PY_FORMAT_SIZE_T "d block%s\n",
fsum, fsum == 1 ? "" : "s",
bc - bf, bc, bc == 1 ? "" : "s");
} }
if (Py_VerboseFlag > 1) { if (Py_VerboseFlag > 1) {
list = block_list; list = block_list;

View File

@ -1296,35 +1296,33 @@ _PyInt_Init(void)
return 1; return 1;
} }
void int
PyInt_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum) PyInt_ClearFreeList(void)
{ {
PyIntObject *p; PyIntObject *p;
PyIntBlock *list, *next; PyIntBlock *list, *next;
unsigned int ctr; int i;
size_t bc = 0, bf = 0; /* block count, number of freed blocks */ int u; /* remaining unfreed ints per block */
size_t isum = 0; /* total unfreed ints */ int freelist_size = 0;
int irem; /* remaining unfreed ints per block */
list = block_list; list = block_list;
block_list = NULL; block_list = NULL;
free_list = NULL; free_list = NULL;
while (list != NULL) { while (list != NULL) {
bc++; u = 0;
irem = 0; for (i = 0, p = &list->objects[0];
for (ctr = 0, p = &list->objects[0]; i < N_INTOBJECTS;
ctr < N_INTOBJECTS; i++, p++) {
ctr++, p++) {
if (PyInt_CheckExact(p) && p->ob_refcnt != 0) if (PyInt_CheckExact(p) && p->ob_refcnt != 0)
irem++; u++;
} }
next = list->next; next = list->next;
if (irem) { if (u) {
list->next = block_list; list->next = block_list;
block_list = list; block_list = list;
for (ctr = 0, p = &list->objects[0]; for (i = 0, p = &list->objects[0];
ctr < N_INTOBJECTS; i < N_INTOBJECTS;
ctr++, p++) { i++, p++) {
if (!PyInt_CheckExact(p) || if (!PyInt_CheckExact(p) ||
p->ob_refcnt == 0) { p->ob_refcnt == 0) {
Py_TYPE(p) = (struct _typeobject *) Py_TYPE(p) = (struct _typeobject *)
@ -1345,15 +1343,12 @@ PyInt_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum)
} }
else { else {
PyMem_FREE(list); PyMem_FREE(list);
bf++;
} }
isum += irem; freelist_size += u;
list = next; list = next;
} }
*pbc = bc; return freelist_size;
*pbf = bf;
*bsum = isum;
} }
void void
@ -1361,12 +1356,10 @@ PyInt_Fini(void)
{ {
PyIntObject *p; PyIntObject *p;
PyIntBlock *list; PyIntBlock *list;
unsigned int ctr; int i;
size_t bc, bf; /* block count, number of freed blocks */ int u; /* total unfreed ints per block */
size_t isum; /* total unfreed ints per block */
#if NSMALLNEGINTS + NSMALLPOSINTS > 0 #if NSMALLNEGINTS + NSMALLPOSINTS > 0
int i;
PyIntObject **q; PyIntObject **q;
i = NSMALLNEGINTS + NSMALLPOSINTS; i = NSMALLNEGINTS + NSMALLPOSINTS;
@ -1376,27 +1369,24 @@ PyInt_Fini(void)
*q++ = NULL; *q++ = NULL;
} }
#endif #endif
PyInt_CompactFreeList(&bc, &bf, &isum); u = PyInt_ClearFreeList();
if (!Py_VerboseFlag) if (!Py_VerboseFlag)
return; return;
fprintf(stderr, "# cleanup ints"); fprintf(stderr, "# cleanup ints");
if (!isum) { if (!u) {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
else { else {
fprintf(stderr, fprintf(stderr,
": %" PY_FORMAT_SIZE_T "d unfreed int%s in %" ": %d unfreed int%s\n",
PY_FORMAT_SIZE_T "d out of %" u, u == 1 ? "" : "s");
PY_FORMAT_SIZE_T "d block%s\n",
isum, isum == 1 ? "" : "s",
bc - bf, bc, bc == 1 ? "" : "s");
} }
if (Py_VerboseFlag > 1) { if (Py_VerboseFlag > 1) {
list = block_list; list = block_list;
while (list != NULL) { while (list != NULL) {
for (ctr = 0, p = &list->objects[0]; for (i = 0, p = &list->objects[0];
ctr < N_INTOBJECTS; i < N_INTOBJECTS;
ctr++, p++) { i++, p++) {
if (PyInt_CheckExact(p) && p->ob_refcnt != 0) if (PyInt_CheckExact(p) && p->ob_refcnt != 0)
/* XXX(twouters) cast refcount to /* XXX(twouters) cast refcount to
long until %zd is universally long until %zd is universally

View File

@ -829,32 +829,12 @@ PyDoc_STRVAR(sys_clear_type_cache__doc__,
Clear the internal type lookup cache."); 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[] = { static PyMethodDef sys_methods[] = {
/* Might as well keep this in alphabetic order */ /* Might as well keep this in alphabetic order */
{"callstats", (PyCFunction)PyEval_GetCallStats, METH_NOARGS, {"callstats", (PyCFunction)PyEval_GetCallStats, METH_NOARGS,
callstats_doc}, callstats_doc},
{"_clear_type_cache", sys_clear_type_cache, METH_NOARGS, {"_clear_type_cache", sys_clear_type_cache, METH_NOARGS,
sys_clear_type_cache__doc__}, 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", sys_current_frames, METH_NOARGS,
current_frames_doc}, current_frames_doc},
{"displayhook", sys_displayhook, METH_O, displayhook_doc}, {"displayhook", sys_displayhook, METH_O, displayhook_doc},