Python:垃圾收集器是否在引发 MemoryError 之前运行?

and*_*chy 5 python memory garbage-collection numpy out-of-memory

在迭代 30 个涉及内存和 CPU 密集型数值计算的问题序列的 Python 代码中,我观察到 Python 进程的内存消耗在 30 次迭代中每次开始时都会增加约 800MB,并最终MemoryError引发第 8 次迭代(系统内存实际上已耗尽)。但是,如果我在每次迭代后import gc运行gc.collect(),那么内存消耗将保持在约 2.5GB 不变,并且 Python 代码在解决所有 30 个问题后会很好地终止。该代码仅使用连续2个问题的数据,并且没有引用周期(否则手动垃圾收集也无法降低内存消耗)。

问题

如果 Python 尝试在引发MemoryError. 在我看来,这将是一件完全理智的事情,但也许有理由反对这样做?

此处进行了与上述类似的观察:https ://stackoverflow.com/a/4319539/1219479

Max*_*oel 4

实际上,存在引用循环,这是手动gc.collect()调用能够回收内存的唯一原因。

在 Python 中(我假设是 CPython),垃圾收集器的唯一目的是打破引用循环。当不存在时,对象将被销毁,并在最后一次对它们的引用丢失时回收它们的内存。

至于垃圾收集器何时运行,完整文档位于: http: //docs.python.org/2/library/gc.html

最重要的是,Python 维护一个对象分配和释放的内部计数器。每当(allocations - deallocations)达到 700(阈值 0)时,就会运行垃圾收集,并且两个计数器都会重置。

每次发生收集(自动或手动运行gc.collect())时,都会收集第 0 代(尚未在收集中幸存的所有对象)(即,遍历没有可访问引用的对象,寻找引用循环 -如果找到任何一个,循环就会被破坏,可能会导致对象被销毁,因为没有留下任何引用)。该集合之后剩余的所有对象都将移至第 1 代。

每 10 次收集(阈值 1),第 1 代也会被收集,并且第 1 代中存活下来的所有对象都会移动到第 2 代。第 1 代的每 10 个收集(即每 100 个收集 - 阈值 2),第 2 代也被收集。幸存下来的对象留在第 2 代中——没有第 3 代。

用户可以通过调用 来设置这 3 个阈值gc.set_threshold(threshold0, threshold1, threshold2)

这一切对您的程序意味着什么:

  1. GC 不是 CPython 用于回收内存的机制(引用计数是)。GC 会破坏“死”对象中的引用循环,这可能会导致其中一些对象被销毁。
  2. 不,不能保证 GC 会在 aMemoryError引发之前运行。
  3. 你有参考周期。尝试摆脱它们。