Why doesn't the memory size change when you delete an item from the list?
是的,为什么从列表中删除项目时大小不改变?有没有办法改变这种行为?
1 2 3 4 5 6 7 8 | Python 2.7.5+ (default, Feb 27 2014, 19:37:08) >>> from sys import getsizeof >>> x = [1, 2, 3, 4] >>> print getsizeof(x), x 104 [1, 2, 3, 4] >>> del x[3] >>> print getsizeof(x), x 104 [1, 2, 3] |
当你添加一个项目时,它通常也不会改变。这是因为
另外,
如果要减少内存消耗,请创建列表的切片副本:
1 2 3 4 5 6 | >>> x = [1]*3 >>> del x[2] >>> sys.getsizeof(x) 88 >>> sys.getsizeof(x[:]) 80 |
不过,这通常是不必要的,而且对每个删除都这样做几乎肯定是一个坏主意。
根据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ... /* 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)) { assert(self->ob_item != NULL || newsize == 0); Py_SIZE(self) = newsize; return 0; } /* This over-allocates proportional to the list size, making room * for additional growth. The over-allocation is mild, but is * enough to give linear-time amortized behavior over a long * sequence of appends() in the presence of a poorly-performing * system realloc(). * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... */ new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6); ... |
仅因为附加或删除了某个项而不可变地调整大小将导致性能不佳。
列表对象不会在每次删除时调整内部C数组的大小;这会非常低效。
当添加元素时,列表对象会根据需要定期过度分配新内存;当删除时,仅当删除的内容足以容纳已分配的一半空间时,才会调整大小。从C代码:
1 2 3 4 5 | if (allocated >= newsize && newsize >= (allocated >> 1)) { assert(self->ob_item != NULL || newsize == 0); Py_SIZE(self) = newsize; return 0; } |
号
其中
即使在缩小列表时,数组仍会被分配过多以接收新元素;列表数组中始终至少有3个插槽是空的。
因此,在删除足够的元素之前,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | >>> from sys import getsizeof >>> x = [1, 2, 3, 4] * 3 >>> x [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4] >>> print getsizeof(x), x 168 [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4] >>> del x[-1] >>> del x[-1] >>> del x[-1] >>> del x[-1] >>> print getsizeof(x), x 168 [1, 2, 3, 4, 1, 2, 3, 4] >>> del x[-1] >>> del x[-1] >>> del x[-1] >>> del x[-1] >>> print getsizeof(x), x 136 [1, 2, 3, 4] |
在另一个方向上,当添加元素时,列表过度分配会按存储的引用数的大小的比例逐步增加列表:
1 2 3 4 5 6 7 8 | /* This over-allocates proportional to the list size, making room * for additional growth. The over-allocation is mild, but is * enough to give linear-time amortized behavior over a long * sequence of appends() in the presence of a poorly-performing * system realloc(). * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... */ new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6); |
。
参见
当然,实际的
最好的猜测是,每次从列表中删除一个项目时,python都不会释放列表的末尾。它会在这个空间上停留一段时间,以防再次需要它。它可能会等到有足够多的空位来保证在一次大的突袭中清除它们。