Having issue about garbage collecting in Python 2.7. Why does this code
class A:
def __init__(self, name):
self.name = name
def __del__(self):
print self.name,
aa = [A(str(i)) for i in range(10)]
del aa
give the output 9 8 7 6 5 4 3 2 1 0 and not 0 1 2 3 4 5 6 7 8 9 or any other permutation.
Because the Python list object decreases the reference counts of the items it references in reverse order:
static void
list_dealloc(PyListObject *op)
{
Py_ssize_t i;
PyObject_GC_UnTrack(op);
Py_TRASHCAN_SAFE_BEGIN(op)
if (op->ob_item != NULL) {
/* Do it backwards, for Christian Tismer.
There's a simple test case where somehow this reduces
thrashing when a *very* large list is created and
immediately deleted. */
i = Py_SIZE(op);
while (--i >= 0) {
Py_XDECREF(op->ob_item[i]);
}
PyMem_FREE(op->ob_item);
}
if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op))
free_list[numfree++] = op;
else
Py_TYPE(op)->tp_free((PyObject *)op);
Py_TRASHCAN_SAFE_END(op)
}
See that comment; removing references starting from the end apparently reduces thrashing in some cases with large lists.
My guess is that when you create a very large list, the last items are still in the cache and dereferencing those first helps reduce cache churn. Add swapping and starting from the end makes an even bigger difference.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With