Index: Include/listobject.h =================================================================== --- Include/listobject.h (revision 77751) +++ Include/listobject.h (working copy) @@ -36,6 +36,7 @@ * the list is not yet visible outside the function that builds it. */ Py_ssize_t allocated; + Py_ssize_t orphans; } PyListObject; PyAPI_DATA(PyTypeObject) PyList_Type; Index: Objects/listobject.c =================================================================== --- Objects/listobject.c (revision 77751) +++ Objects/listobject.c (working copy) @@ -27,12 +27,28 @@ PyObject **items; size_t new_allocated; Py_ssize_t allocated = self->allocated; + Py_ssize_t needed; + if (self->orphans == 1000) { + items = self->ob_item - self->orphans; + memmove(items, &items[self->orphans], + (newsize)*sizeof(PyObject *)); + self->ob_item = items; + self->orphans = 0; + } + + needed = newsize + self->orphans; + + /* + fprintf(stderr, "Orphans: %" PY_FORMAT_SIZE_T "d\n", + self->orphans); + */ + /* Bypass realloc() when a previous overallocation is large enough to accommodate the newsize. If the newsize falls lower than half the allocated size, then proceed with the realloc() to shrink the list. */ - if (allocated >= newsize && newsize >= (allocated >> 1)) { + if (allocated >= needed && needed >= (allocated >> 1)) { assert(self->ob_item != NULL || newsize == 0); Py_SIZE(self) = newsize; return 0; @@ -45,28 +61,33 @@ * system realloc(). * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... */ - new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6); + new_allocated = (needed >> 3) + (needed < 9 ? 3 : 6); /* check for integer overflow */ - if (new_allocated > PY_SIZE_MAX - newsize) { + if (new_allocated > PY_SIZE_MAX - needed) { PyErr_NoMemory(); return -1; } else { - new_allocated += newsize; + new_allocated += needed; } - if (newsize == 0) + if (needed == 0) new_allocated = 0; - items = self->ob_item; - if (new_allocated <= ((~(size_t)0) / sizeof(PyObject *))) + items = self->ob_item - self->orphans; + /* + fprintf(stderr, "ob_item: %p", self->ob_item); + fprintf(stderr, "items: %p", items); + */ + if (new_allocated <= ((~(size_t)0) / sizeof(PyObject *))) { PyMem_RESIZE(items, PyObject *, new_allocated); + } else items = NULL; if (items == NULL) { PyErr_NoMemory(); return -1; } - self->ob_item = items; + self->ob_item = items + self->orphans; Py_SIZE(self) = newsize; self->allocated = new_allocated; return 0; @@ -158,6 +179,7 @@ } Py_SIZE(op) = size; op->allocated = size; + op->orphans = 0; _PyObject_GC_TRACK(op); return (PyObject *) op; } @@ -306,9 +328,9 @@ immediately deleted. */ i = Py_SIZE(op); while (--i >= 0) { - Py_XDECREF(op->ob_item[i]); + Py_XDECREF(op->ob_item[i+op->orphans]); } - PyMem_FREE(op->ob_item); + PyMem_FREE(op->ob_item - op->orphans); } if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) free_list[numfree++] = op; @@ -638,8 +660,14 @@ memcpy(recycle, &item[ilow], s); if (d < 0) { /* Delete -d items */ - memmove(&item[ihigh+d], &item[ihigh], - (Py_SIZE(a) - ihigh)*sizeof(PyObject *)); + if (ilow == 0) { + a->orphans += 1; + a->ob_item += (-1 * d); + } + else { + memmove(&item[ihigh+d], &item[ihigh], + (Py_SIZE(a) - ihigh)*sizeof(PyObject *)); + } list_resize(a, Py_SIZE(a) + d); item = a->ob_item; }