Commit a84f3abb authored by Raymond Hettinger's avatar Raymond Hettinger

SF #1022910: Conserve memory with list.pop()

The list resizing scheme only downsized when more than 16 elements were
removed in a single step:  del a[100:120].   As a result, the list would
never shrink when popping elements off one at a time.

This patch makes it shrink whenever more than half of the space is unused.

Also, at Tim's suggestion, renamed _new_size to new_allocated.  This makes
the code easier to understand.
parent 0e9980f7
...@@ -25,13 +25,14 @@ static int ...@@ -25,13 +25,14 @@ static int
list_resize(PyListObject *self, int newsize) list_resize(PyListObject *self, int newsize)
{ {
PyObject **items; PyObject **items;
size_t _new_size; size_t new_allocated;
int allocated = self->allocated;
/* Bypass realloc() when a previous overallocation is large enough /* Bypass realloc() when a previous overallocation is large enough
to accommodate the newsize. If the newsize is 16 smaller than the to accommodate the newsize. If the newsize falls lower than half
current size, then proceed with the realloc() to shrink the list. the allocated size, then proceed with the realloc() to shrink the list.
*/ */
if (self->allocated >= newsize && self->ob_size < newsize + 16) { if (allocated >= newsize && newsize >= (allocated >> 1)) {
assert(self->ob_item != NULL || newsize == 0); assert(self->ob_item != NULL || newsize == 0);
self->ob_size = newsize; self->ob_size = newsize;
return 0; return 0;
...@@ -44,10 +45,12 @@ list_resize(PyListObject *self, int newsize) ...@@ -44,10 +45,12 @@ list_resize(PyListObject *self, int newsize)
* system realloc(). * system realloc().
* The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
*/ */
_new_size = (newsize >> 3) + (self->ob_size < 8 ? 3 : 6) + newsize; new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
if (newsize == 0)
new_allocated = 0;
items = self->ob_item; items = self->ob_item;
if (_new_size <= ((~(size_t)0) / sizeof(PyObject *))) if (new_allocated <= ((~(size_t)0) / sizeof(PyObject *)))
PyMem_RESIZE(items, PyObject *, _new_size); PyMem_RESIZE(items, PyObject *, new_allocated);
else else
items = NULL; items = NULL;
if (items == NULL) { if (items == NULL) {
...@@ -56,7 +59,7 @@ list_resize(PyListObject *self, int newsize) ...@@ -56,7 +59,7 @@ list_resize(PyListObject *self, int newsize)
} }
self->ob_item = items; self->ob_item = items;
self->ob_size = newsize; self->ob_size = newsize;
self->allocated = _new_size; self->allocated = new_allocated;
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment