0

我们的对象是一个大系统。我们知道现在肯定有一些内存泄漏。但是很难找到原因。每次进程使用的内存达到千兆字节时,它的响应都非常慢。从“顶部”查看的 cpu 使用率始终为 100%,即使进程无事可做。

我们已经使用 objgraph 和 meliae 来调试过这个问题,没什么好怀疑的。但是我们发现了一个奇怪的问题,gc.get_objects() 得到的对象的总大小与从“top”查看的内存使用不相等,例如它是50M,但从“top”看是150M。

谁能给我们一个方向?谢谢。

4

1 回答 1

6

我假设您通过以下方式获取对象的大小:

sum(sys.getsizeof(i) for i in gc.get_objects())

请记住,结果gc.get_objects()不包括解释器本身消耗的内存,只包括垃圾收集器跟踪的 Python 对象。此外,这个函数依赖于对象从他们的__sizeof__()方法返回准确的结果,所以如果你使用任何第三方模块,那么你不一定期望得到准确的结果。

您可能已经这样做了,但是您可以让您的应用程序定期调用gc.collect(),然后检查gc.garbage您是否有任何收集器无法释放的无法访问的对象。如果您有任何具有循环引用的类被您覆盖__del__()(请参阅Python 文档中的 gc),就会出现这种情况。

我还建议将此调用添加到代码的开头:

gc.set_debug(gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_INSTANCES | gc.DEBUG_OBJECTS)

stderr这将在找到带有循环引用等的对象时打印消息。这可能会为您提供有关更仔细查看位置的有用信息。

到目前为止,objgraph 可能已经发现了这些类型的问题,但无论如何都值得将它们放入,因为您可以让它们在长期运行的守护程序中保持活动状态,以便随着时间的推移记录这些问题发生的时间。

如果您使用任何 C 扩展(无论是您自己编写的还是第三方编写的),请仔细检查代码是否存在处理引用计数的错误——在那里很容易出错。另外,请记住,没有什么可以阻止扩展在 Python 的分配器之外分配自己的内存 - 在这种情况下,如果这些泄漏,您在 Python 解释器中所做的任何事情都不会检测到它。

综上所述,如果您仍然看到内存使用量单调增加,并且找不到任何导致原因的 Python 对象,那么可能是时候检查低级 C 代码或 Python 解释器本身是否存在泄漏 - 一个很好的工具因为这是Valgrind

要将 Valgrind 与 Python 一起使用,您需要使用Python 抑制文件。您可能会发现它已经安装了 - 例如,Ubuntu 将此文件的修改形式放在/usr/lib/valgrind/python.supp.

要正确执行此操作,您需要按照 Python 发行版中的README.valgrind文件中的描述重新编译 Python,但即使没有这个,您也可能会发现一些有趣的结果。

在这个堆栈溢出问题中有更多关于在 Valgrind 下运行 Python 的讨论。

于 2013-01-08T12:29:59.190 回答