Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python garbage collector and list [duplicate]

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.

like image 930
alexvassel Avatar asked May 24 '26 03:05

alexvassel


1 Answers

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.

like image 67
Martijn Pieters Avatar answered May 26 '26 16:05

Martijn Pieters