为什么禁用垃圾收集器?

ger*_*rit 20 python garbage-collection

Pythons gc.disable禁用自动垃圾收集.据我了解,这会产生一些副作用.为什么有人想要禁用自动垃圾收集,如何在没有自动垃圾收集的情况下有效管理内存?

unu*_*tbu 20

禁用垃圾收集器的一个用途是在计算代码性能时获得更一致的结果.timeit模块执行此操作.

def timeit(self, number=default_number):
    if itertools:
        it = itertools.repeat(None, number)
    else:
        it = [None] * number
    gcold = gc.isenabled()
    gc.disable()
    ...
Run Code Online (Sandbox Code Playgroud)

在Python2Python3.2 gc.disable()中也用于避免fork和之间发生的垃圾收集引起的错误exec.这个问题似乎已在Python3.3中修复,无需调用gc.disable().


Jam*_*lls 7

另一个用例是手动控制垃圾收集gc.collect()


Ste*_*sop 7

在您链接到的同一页面上:

由于收集器补充了Python中已经使用的引用计数,因此如果您确定程序不创建引用循环,则可以禁用收集器.

所以这回答了问题的第二部分,"如何在没有它的情况下有效地管理记忆".不要创建参考周期.当然,这是一个相当有限的用例.

对于问题的第一部分,答案是表现.同样,一个相当有限的用例.

禁用GC只会在以下情况下有所帮助:(a)GC实际上正在工作,(b)工作没有实现任何目的,也就是说它没有找到任何可以解放的东西,或者发现你认为你的程序可以容忍泄漏只要GC被禁用.因此,如果您的程序太慢并且没有创建参考周期并且禁用GC似乎加速了它,那么您将考虑禁用GC.

我推测(基于我之前见过的GC,特别是Python),如果你没有分配任何内存,那么垃圾收集器将不会有任何长期的性能成本.它可能会有一些短期和不可预测的成本,可以整理以前的成本.所以,即使你正在进行大规模的numpy数字运算,并认为你应该从代码的那一部分中挤出所有可能的性能,但在你这样做时禁用GC仍然无济于事.它只会延迟整理先前参考周期的时间成本,直到重新启用GC为止.

可以说,运行时间短且不占用大量内存的程序不需要垃圾回收,它们可以容忍泄漏.但更有说服力的是,如果你开始这样思考,你最终会遇到一个泄漏了比预期更多内存的程序.

  • 问题在于,在实践中,很难(没有边界线)来确保您没有参考周期。您可以轻松地确保您的代码没有,但是您的依赖项又如何呢?由于模块,函数和类通常不指定是否创建引用循环,因此您将必须遍历每个依赖项和传递性依赖项(包括标准库)的代码,并验证是否未创建此类引用。当然,升级依赖项可能会引入一个周期。 (2认同)
  • @凯文:绝对。我认为我打算“相当有限”是一种讽刺性的轻描淡写。 (2认同)

Alf*_*lfe 6

启用GC的问题始终是您不知道何时会发生.因此,如果您的程序(部分)是时间关键的,需要实时等,那么您可以在程序运行的时间(该部分)中禁用GC.

是否要稍后再次打开自动GC,或者如果您希望通过调用手动执行此操作,gc.collect()则无关紧要.

此外,一些程序设计为只运行很短的时间,因此开发人员可以确保在此期间不会出现任何内存问题(考虑像ls这样的程序); 然后可以忽略整个GC方面以支持性能.