为什么要禁用垃圾回收器?

33

Python的gc.disable可以禁用自动垃圾回收。据我所知,这将产生相当多的副作用。为什么有人要禁用自动垃圾回收,并且在没有它的情况下如何有效地管理内存?

4个回答

33

10

从您提供的页面中可以看到:

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

这回答了问题的第二部分,“如何在没有它的情况下有效地管理内存”。不要创建引用循环。当然,这是一个相当有限的用例。

对于问题的第一部分,答案是性能。同样,这也是一个相当有限的用例。

如果(a)垃圾收集器实际上在工作,并且(b)该工作没有取得任何成果,即它没有找到任何可释放的内容或者发现很少,以至于您认为您的程序可以容忍暂时的泄漏而不需要收集,则禁用GC才会有所帮助。因此,如果您的程序太慢,并且不会创建引用循环,并且禁用 GC 看起来可以加快速度,那么您将考虑禁用 GC。

我推测(基于我之前见过的垃圾收集器,而不是特别针对 Python 的)如果您没有分配任何内存,那么垃圾收集器就不会有任何长期的性能成本。它可能会在清理之前有一些短期和不可预测的成本。因此,即使在您进入一个大规模的 numpy 数学计算程序,并认为应该从代码中挤出所有可能的性能时,禁用 GC 也是没有帮助的。它只会推迟清理之前的引用循环所需的时间成本,直到您重新启用 GC。

可以说,运行时间短且不占用太多内存的程序不需要垃圾回收,它们可以容忍泄漏。但更值得注意的是,如果您从一开始就这样思考,最终可能会遇到比预期泄露更多的内存程序而导致麻烦。


4
问题在于,实际上很难(边缘情况下是不可能的)确保不存在引用循环。你可以轻松地确保自己的代码不会出现引用循环,但是对于你所依赖的库有什么样的情况呢?由于模块、函数和类通常不指定它们是否创建引用循环,你需要检查每个依赖项和传递依赖项的代码(包括标准库),以验证没有这样的引用关系。当然,升级依赖项可能会引入一个循环引用。 - Kevin
2
@Kevin:完全正确。我想我本来想说“相当有限”是一种讽刺的轻描淡写。 - Steve Jessop

6
另一个用例是使用gc.collect()手动控制垃圾回收。

1
但是,禁用GC首先是使用gc.collect()的要求吗?或者gc.collect()的用例是什么?(注意:我实际上曾经在一个C#应用程序中遇到过这样的用例,在<512MiB的框中内存不足) - Sebastian Mach
1
据我所知,您可以随时调用“gc.collect()”。 - James Mills
一个独立的问题是这样的指令是否会被垃圾回收器快速执行(如果有的话)(我持怀疑态度,因为JVM可能会永远忽略这样的指令,并且按设计:https://dev59.com/8V0a5IYBdhLWcg3wHlil#30690392)。 - mirekphd

6
启用垃圾回收机制的问题在于,你不知道它何时会发生。因此,如果(部分)程序具有时间关键性、需要实时等特点,则可以在(该部分)程序运行期间禁用GC。无论您是希望稍后再次开启自动GC,还是更喜欢手动调用 `gc.collect()`,都不影响这个问题。此外,一些程序只设计运行很短的时间,因此开发人员可能可以确保在此期间不会出现任何内存问题(考虑像ls这样的程序);那么整个GC方面就可以忽略,以提高性能。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接