python在循环迭代结束时进行垃圾收集吗?

时间:2016-04-19 20:53:38

标签: python loops garbage-collection multiprocessing

请注意这个简单的代码:

    import random
    while True:
        L = list( str(random.random()))

问题:如果我让这个运行,python是否会耗尽内存?
我问的原因是:
该循环的第一次迭代,创建了一个列表,并且' L'被指定代表该列表。该循环的下一次迭代,创建另一个列表,' L'从上一个列表中拉出并分配给新列表。之前的列表已经失去了参考。以前的清单是垃圾收集的吗?如果不是在每次迭代结束时,但最终我希望?

话虽如此,只需将场景进一步扩展到多处理:

    import random
    while True:
        l1 = list( str(random.random()))            
        pseudo: multiprocessing.Queue.put(l1)
        # how is l1 handled here?
        # is l1 .copy()-ed to the queue or referenced by the queue?
        # is l1 destoryed in this process (this while loop) at the end of iteration?

2 个答案:

答案 0 :(得分:3)

垃圾收集的主要方法是CPython中的引用计数(语言的参考实现)。当不再有对象的引用时,它占用的内存会立即释放,并且可以被其他Python对象重用。 (它可能会也可能不会被释放回操作系统。)从未释放的对象有一些例外:小整数,实习字符串(包括文字),空元组None

因此,为了回答您的初始问题,L将在每次迭代时重新分配到新列表。此时,前一个列表没有引用,其内存将立即释放。

关于你的第二个例子,将某些东西放入multiprocessing队列是必要的复制操作。该对象必须被序列化(" pickle"用Python的说法)发送到新进程,该进程有自己的内存空间,无法从原始进程的内存中看到任何内容。当您在循环中将li重新分配到下一个列表时,之前的列表没有引用,并且将再次被释放。

在循环结束时,Ll1变量仍然引用一个列表:您在循环的最后一次迭代中创建的列表。如果您要发布此对象,请分别del Ldel l1

PS - 当对象包含对它们自己的引用时(直接或间接通过其他对象链),这被称为循环引用。这些不是通过引用计数自动收集的,Python有一个单独的垃圾收集器,它定期运行以清理它们。

答案 1 :(得分:2)

通过向类中添加自定义__del__命令来观察发生的情况,我们可以轻松地对此进行测试:

class WithDestructor(object):
   def __del__(self):
       print(f"Exploding {self}")

Q=None
for i in range(5):
    Q = WithDestructor()
    print(f"In loop {i}")

如果清除仅发生在循环的最后,我们将得到循环输出,然后是析构函数输出。相反,我将其隔行扫描,因此Q中的对象在重新分配Q时立即得到清理。

In loop 0
Exploding <__main__.WithDestructor object at 0x7f93141176d8>
In loop 1
Exploding <__main__.WithDestructor object at 0x7f93141172b0>
In loop 2
Exploding <__main__.WithDestructor object at 0x7f93141176d8>
In loop 3
Exploding <__main__.WithDestructor object at 0x7f93141172b0>
In loop 4