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

2024-03-04

在迭代 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 https://stackoverflow.com/a/4319539/1219479


其实,有are参考周期,这是手册的唯一原因gc.collect()调用完全可以回收内存。

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

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

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

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

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

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

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

  1. GC 不是 CPython 用来回收内存的机制(引用计数是)。 GC 会破坏“死”对象中的引用循环,这可能会导致其中一些对象被销毁。
  2. 不,不能保证 GC 会在MemoryError被提出。
  3. 你有参考周期。尝试摆脱它们。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python:垃圾收集器是否在引发 MemoryError 之前运行? 的相关文章

随机推荐