【问题标题】:Python garbage collectionPython 垃圾回收
【发布时间】:2010-11-05 08:23:22
【问题描述】:

我创建了一些 python 代码,它在循环中创建一个对象,并且在每次迭代中都用一个相同类型的新对象覆盖这个对象。这样做了 10.000 次,Python 每秒占用 7mb 内存,直到我的 3gb RAM 被使用。有谁知道从内存中删除对象的方法?

【问题讨论】:

标签: python optimization memory-management garbage-collection


【解决方案1】:

我认为这是循环引用(尽管问题并未明确说明此信息。)

解决此问题的一种方法是手动调用垃圾回收。当您手动运行垃圾收集器时,它也会清除循环引用的对象。

import gc

for i in xrange(10000):
    j = myObj()
    processObj(j)
    #assuming count reference is not zero but still
    #object won't remain usable after the iteration

    if !(i%100):
        gc.collect()

这里不要太频繁地运行垃圾收集器,因为它有自己的开销,例如如果你在每个循环中运行垃圾收集器,解释会变得非常慢。

【讨论】:

    【解决方案2】:

    您没有提供足够的信息 - 这取决于您正在创建的对象的具体情况以及您在循环中使用它执行的其他操作。如果对象未创建循环引用,则应在下一次迭代时将其释放。比如代码

    for x in range(100000):
      obj = " " * 10000000
    

    不会导致内存分配不断增加。

    【讨论】:

    • 我正在我的对象中创建循环引用。不能手动删除吗?
    • Python 会自动收集带有循环引用的对象,除非引用循环中的任何对象都有 del 方法。如果是这种情况,垃圾对象将被移动到 gc.garbage 列表中,您将不得不手动中断引用循环。最好尽量避免同时使用 del 方法和引用循环。
    • 避免引用循环的一种解决方案是使用弱引用:docs.python.org/library/weakref.html
    【解决方案3】:

    这是一个旧错误,在 python 2.5 中已针对某些类型进行了更正。发生的事情是 python 不太擅长收集空列表/字典/tupes/floats/ints 之类的东西。在 python 2.5 中,这是固定的……主要是。然而,浮点数和整数是用于比较的单例,因此一旦创建了其中一个,只要解释器​​还活着,它就会一直存在。在处理大量花车时,我一直被这种最糟糕的情况所困扰,因为它们有一个令人讨厌的独特习惯。这被描述为for python 2.4,并更新了它被折叠成python 2.5

    我发现的最好的方法是升级到 python 2.5 或更新版本来处理列表/字典/元组问题。对于数字,唯一的解决方案是不要让大量数字进入 python。我已经用自己的 c++ 对象包装器完成了它,但我的印象是 numpy.array 会给出类似的结果。

    作为一个后置脚本,我不知道在 python 3 中发生了什么,但我怀疑数字仍然是单例的一部分。所以内存泄漏其实是语言的一个特性。

    【讨论】:

    • 不过,这不应该完全对所描述的问题负责;甚至 Python 2.4 也应该重用释放的内存(只是没有将其返回给操作系统)。
    • 不确定我的实验是否正确,但暂时创建数百万个浮点数肯定会持续使用内存。将相同的浮点数放入 list 会增加 100MB/s 的内存使用量。那是在 2.7 上...所以我猜至少在 2.7 中问题不会退出?我错过了什么吗?
    【解决方案4】:

    如果您正在创建循环引用,您的对象不会立即被释放,而是必须等待 GC 循环运行。

    您可以使用weakref 模块来解决这个问题,或者在使用后显式删除您的对象。

    【讨论】:

      【解决方案5】:

      我发现在我的情况下(使用 Python 2.5.1),循环引用涉及具有 __del__() 方法的类,不仅垃圾收集没有及时发生,我的对象的 __del__() 方法是即使脚本退出,也永远不会被调用。所以我用weakref 打破了循环引用,一切都很好。

      感谢 Miles,他在他的 cmets 中提供了所有信息,让我把这些信息放在一起。

      【讨论】:

      【解决方案6】:

      您可以在 REPL 执行以下操作来强制取消引用变量:

      >>> x = 5
      >>> x
      5
      >>> del x
      >>> x
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
      NameError: name 'x' is not defined
      

      【讨论】:

      • 在典型的程序中,让变量超出范围比显式删除它们更容易和更清晰。当然,如果你的整个程序是一个单一的长函数,那么在它结束之前没有什么会超出范围。这是不推荐使用单个长函数编写程序的原因之一。
      【解决方案7】:

      weakref 可用于循环对象结构化代码,如explained example

      【讨论】:

        猜你喜欢
        • 2011-12-21
        • 2012-01-28
        • 2013-06-27
        • 2011-11-29
        • 2021-12-20
        • 2011-07-15
        • 2014-03-09
        • 2013-06-10
        • 1970-01-01
        相关资源
        最近更新 更多