Skip to content

Commit fd0aee9

Browse files
author
gregory.p.smith
committed
- 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(). git-svn-id: http://svn.python.org/projects/python/trunk@64753 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 05c078a commit fd0aee9

11 files changed

Lines changed: 62 additions & 107 deletions

File tree

Doc/c-api/float.rst

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,9 @@ Floating Point Objects
8686
.. versionadded:: 2.6
8787

8888

89-
.. cfunction:: void PyFloat_CompactFreeList(size_t *bc, size_t *bf, size_t *sum)
89+
.. cfunction:: int PyFloat_ClearFreeList(void)
9090

91-
Compact the float free list. *bc* is the number of allocated blocks before
92-
blocks are freed, *bf* is the number of freed blocks and *sum* is the number
93-
of remaining objects in the blocks.
91+
Clear the float free list. Return the number of items that could not
92+
be freed.
9493

9594
.. versionadded:: 2.6

Doc/c-api/int.rst

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,9 @@ Plain Integer Objects
122122
(:const:`LONG_MAX`, as defined in the system header files).
123123

124124

125-
.. cfunction:: void PyInt_CompactFreeList(size_t *bc, size_t *bf, size_t *sum)
125+
.. cfunction:: int PyInt_ClearFreeList(void)
126126

127-
Compact the integer free list. *bc* is the number of allocated blocks before
128-
blocks are freed, *bf* is the number of freed blocks and *sum* is the number
129-
of remaining objects in the blocks.
127+
Clear the integer free list. Return the number of items that could not
128+
be freed.
130129

131130
.. versionadded:: 2.6

Doc/library/gc.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ The :mod:`gc` module provides the following functions:
4747
.. versionchanged:: 2.5
4848
The optional *generation* argument was added.
4949

50+
.. versionchanged:: 2.6
51+
The free lists maintained for a number of builtin types are cleared
52+
whenever a full collection or collection of the highest generation (2)
53+
is run. Not all items in some free lists may be freed due to the
54+
particular implementation, in particular :class:`int` and :class:`float`.
55+
5056

5157
.. function:: set_debug(flags)
5258

Doc/library/sys.rst

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -58,22 +58,6 @@ always available.
5858
A string containing the copyright pertaining to the Python interpreter.
5959

6060

61-
.. function:: _compact_freelists()
62-
63-
Compact the free lists of integers and floats by deallocating unused blocks.
64-
It can reduce the memory usage of the Python process several tenth of
65-
thousands of integers or floats have been allocated at once.
66-
67-
The return value is a tuple of tuples each containing three elements,
68-
amount of used objects, total block count before the blocks are deallocated
69-
and amount of freed blocks. The first tuple refers to ints, the second to
70-
floats.
71-
72-
This function should be used for specialized purposes only.
73-
74-
.. versionadded:: 2.6
75-
76-
7761
.. function:: _clear_type_cache()
7862

7963
Clear the internal type cache. The type cache is used to speed up attribute

Include/floatobject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ PyAPI_FUNC(double) _PyFloat_Unpack4(const unsigned char *p, int le);
113113
PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le);
114114

115115
/* free list api */
116-
PyAPI_FUNC(void) PyFloat_CompactFreeList(size_t *, size_t *, size_t *);
116+
PyAPI_FUNC(int) PyFloat_ClearFreeList(void);
117117

118118
/* Format the object based on the format_spec, as defined in PEP 3101
119119
(Advanced String Formatting). */

Include/intobject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ PyAPI_FUNC(unsigned long) PyOS_strtoul(char *, char **, int);
6060
PyAPI_FUNC(long) PyOS_strtol(char *, char **, int);
6161

6262
/* free list api */
63-
PyAPI_FUNC(void) PyInt_CompactFreeList(size_t *, size_t *, size_t *);
63+
PyAPI_FUNC(int) PyInt_ClearFreeList(void);
6464

6565
/* Convert an integer to the given base. Returns a string.
6666
If base is 2, 8 or 16, add the proper prefix '0b', '0o' or '0x'.

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ Core and Builtins
2929
would not cause a syntax error. This was regression from 2.4 caused by the
3030
switch to the new compiler.
3131

32+
- Issue #2862: Make int and float freelist management consistent with other
33+
freelists. Changes their CompactFreeList apis into ClearFreeList apis and
34+
calls them via gc.collect().
35+
3236
Library
3337
-------
3438

Modules/gcmodule.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,8 @@ clear_freelists(void)
736736
(void)PyCFunction_ClearFreeList();
737737
(void)PyTuple_ClearFreeList();
738738
(void)PyUnicode_ClearFreeList();
739+
(void)PyInt_ClearFreeList();
740+
(void)PyFloat_ClearFreeList();
739741
}
740742

741743
/* This is the main function. Read this to understand how the

Objects/floatobject.c

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,30 +1608,28 @@ _PyFloat_Init(void)
16081608
PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc);
16091609
}
16101610

1611-
void
1612-
PyFloat_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum)
1611+
int
1612+
PyFloat_ClearFreeList(void)
16131613
{
16141614
PyFloatObject *p;
16151615
PyFloatBlock *list, *next;
1616-
unsigned i;
1617-
size_t bc = 0, bf = 0; /* block count, number of freed blocks */
1618-
size_t fsum = 0; /* total unfreed ints */
1619-
int frem; /* remaining unfreed ints per block */
1616+
int i;
1617+
int u; /* remaining unfreed ints per block */
1618+
int freelist_size = 0;
16201619

16211620
list = block_list;
16221621
block_list = NULL;
16231622
free_list = NULL;
16241623
while (list != NULL) {
1625-
bc++;
1626-
frem = 0;
1624+
u = 0;
16271625
for (i = 0, p = &list->objects[0];
16281626
i < N_FLOATOBJECTS;
16291627
i++, p++) {
16301628
if (PyFloat_CheckExact(p) && Py_REFCNT(p) != 0)
1631-
frem++;
1629+
u++;
16321630
}
16331631
next = list->next;
1634-
if (frem) {
1632+
if (u) {
16351633
list->next = block_list;
16361634
block_list = list;
16371635
for (i = 0, p = &list->objects[0];
@@ -1646,41 +1644,34 @@ PyFloat_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum)
16461644
}
16471645
}
16481646
else {
1649-
PyMem_FREE(list); /* XXX PyObject_FREE ??? */
1650-
bf++;
1647+
PyMem_FREE(list);
16511648
}
1652-
fsum += frem;
1649+
freelist_size += u;
16531650
list = next;
16541651
}
1655-
*pbc = bc;
1656-
*pbf = bf;
1657-
*bsum = fsum;
1652+
return freelist_size;
16581653
}
16591654

16601655
void
16611656
PyFloat_Fini(void)
16621657
{
16631658
PyFloatObject *p;
16641659
PyFloatBlock *list;
1665-
unsigned i;
1666-
size_t bc, bf; /* block count, number of freed blocks */
1667-
size_t fsum; /* total unfreed floats per block */
1660+
int i;
1661+
int u; /* total unfreed floats per block */
16681662

1669-
PyFloat_CompactFreeList(&bc, &bf, &fsum);
1663+
u = PyFloat_ClearFreeList();
16701664

16711665
if (!Py_VerboseFlag)
16721666
return;
16731667
fprintf(stderr, "# cleanup floats");
1674-
if (!fsum) {
1668+
if (!u) {
16751669
fprintf(stderr, "\n");
16761670
}
16771671
else {
16781672
fprintf(stderr,
1679-
": %" PY_FORMAT_SIZE_T "d unfreed float%s in %"
1680-
PY_FORMAT_SIZE_T "d out of %"
1681-
PY_FORMAT_SIZE_T "d block%s\n",
1682-
fsum, fsum == 1 ? "" : "s",
1683-
bc - bf, bc, bc == 1 ? "" : "s");
1673+
": %d unfreed float%s\n",
1674+
u, u == 1 ? "" : "s");
16841675
}
16851676
if (Py_VerboseFlag > 1) {
16861677
list = block_list;

Objects/intobject.c

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,35 +1296,33 @@ _PyInt_Init(void)
12961296
return 1;
12971297
}
12981298

1299-
void
1300-
PyInt_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum)
1299+
int
1300+
PyInt_ClearFreeList(void)
13011301
{
13021302
PyIntObject *p;
13031303
PyIntBlock *list, *next;
1304-
unsigned int ctr;
1305-
size_t bc = 0, bf = 0; /* block count, number of freed blocks */
1306-
size_t isum = 0; /* total unfreed ints */
1307-
int irem; /* remaining unfreed ints per block */
1304+
int i;
1305+
int u; /* remaining unfreed ints per block */
1306+
int freelist_size = 0;
13081307

13091308
list = block_list;
13101309
block_list = NULL;
13111310
free_list = NULL;
13121311
while (list != NULL) {
1313-
bc++;
1314-
irem = 0;
1315-
for (ctr = 0, p = &list->objects[0];
1316-
ctr < N_INTOBJECTS;
1317-
ctr++, p++) {
1312+
u = 0;
1313+
for (i = 0, p = &list->objects[0];
1314+
i < N_INTOBJECTS;
1315+
i++, p++) {
13181316
if (PyInt_CheckExact(p) && p->ob_refcnt != 0)
1319-
irem++;
1317+
u++;
13201318
}
13211319
next = list->next;
1322-
if (irem) {
1320+
if (u) {
13231321
list->next = block_list;
13241322
block_list = list;
1325-
for (ctr = 0, p = &list->objects[0];
1326-
ctr < N_INTOBJECTS;
1327-
ctr++, p++) {
1323+
for (i = 0, p = &list->objects[0];
1324+
i < N_INTOBJECTS;
1325+
i++, p++) {
13281326
if (!PyInt_CheckExact(p) ||
13291327
p->ob_refcnt == 0) {
13301328
Py_TYPE(p) = (struct _typeobject *)
@@ -1345,28 +1343,23 @@ PyInt_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum)
13451343
}
13461344
else {
13471345
PyMem_FREE(list);
1348-
bf++;
13491346
}
1350-
isum += irem;
1347+
freelist_size += u;
13511348
list = next;
13521349
}
13531350

1354-
*pbc = bc;
1355-
*pbf = bf;
1356-
*bsum = isum;
1351+
return freelist_size;
13571352
}
13581353

13591354
void
13601355
PyInt_Fini(void)
13611356
{
13621357
PyIntObject *p;
13631358
PyIntBlock *list;
1364-
unsigned int ctr;
1365-
size_t bc, bf; /* block count, number of freed blocks */
1366-
size_t isum; /* total unfreed ints per block */
1359+
int i;
1360+
int u; /* total unfreed ints per block */
13671361

13681362
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
1369-
int i;
13701363
PyIntObject **q;
13711364

13721365
i = NSMALLNEGINTS + NSMALLPOSINTS;
@@ -1376,27 +1369,24 @@ PyInt_Fini(void)
13761369
*q++ = NULL;
13771370
}
13781371
#endif
1379-
PyInt_CompactFreeList(&bc, &bf, &isum);
1372+
u = PyInt_ClearFreeList();
13801373
if (!Py_VerboseFlag)
13811374
return;
13821375
fprintf(stderr, "# cleanup ints");
1383-
if (!isum) {
1376+
if (!u) {
13841377
fprintf(stderr, "\n");
13851378
}
13861379
else {
13871380
fprintf(stderr,
1388-
": %" PY_FORMAT_SIZE_T "d unfreed int%s in %"
1389-
PY_FORMAT_SIZE_T "d out of %"
1390-
PY_FORMAT_SIZE_T "d block%s\n",
1391-
isum, isum == 1 ? "" : "s",
1392-
bc - bf, bc, bc == 1 ? "" : "s");
1381+
": %d unfreed int%s\n",
1382+
u, u == 1 ? "" : "s");
13931383
}
13941384
if (Py_VerboseFlag > 1) {
13951385
list = block_list;
13961386
while (list != NULL) {
1397-
for (ctr = 0, p = &list->objects[0];
1398-
ctr < N_INTOBJECTS;
1399-
ctr++, p++) {
1387+
for (i = 0, p = &list->objects[0];
1388+
i < N_INTOBJECTS;
1389+
i++, p++) {
14001390
if (PyInt_CheckExact(p) && p->ob_refcnt != 0)
14011391
/* XXX(twouters) cast refcount to
14021392
long until %zd is universally

0 commit comments

Comments
 (0)