我决定将我的评论转变为答案,以使事情变得更清楚。
从Python 2.5开始,cpython内存分配跟踪小型对象分配器的内部内存使用情况,并尝试将完全空闲的竞技场返回给基础OS。这在大多数情况下都有效,但是对象无法在内存中移动的事实意味着碎片可能是一个严重的问题。
尝试以下实验(我使用3.2,但如果使用xrange,则2.5+应该类似):
# Create the big lists in advance to avoid skewing the memory counts
seq1 = [None] * 10**6 # Big list of references to None
seq2 = seq1[::10]
# Create and reference a lot of smaller lists
seq1[:] = [[] for x in range(10**6)] # References all the new lists
seq2[:] = seq1[::10] # Grab a second reference to 10% of the new lists
# Memory fragmentation in action
seq1[:] = [None] * 10**6 # 90% of the lists are no longer referenced here
seq2[:] = seq1[::10] # But memory freed only after last 10% are dropped
请注意,即使您删除对seq1
和的引用seq2
,上述序列也可能会使您的Python进程拥有大量额外的内存。
当人们谈论PyPy使用的内存少于cpython时,这是他们所谈论内容的重要部分。因为PyPy在后台不使用直接指针引用,所以它可以使用压缩GC,从而避免了很多碎片问题,并更可靠地将内存返回给OS。