我们的目标是一个很大的系统。 我们知道现在必须有一些内存泄漏。但要找到原因是如此困难。每次进程使用的内存达到千兆字节时,它的响应都很慢。 从“顶部”看到的cpu使用率是100%,即使这个过程也没有工作要做。
我们使用objgraph和meliae来调试这个问题,没有什么可怀疑的。但是我们发现了一个奇怪的问题,gc.get_objects()得到的对象的总大小与从“top”看到的内存使用量不相等,例如它是50M,但是距离“top”是150M。
有人能指点我们吗?感谢。
答案 0 :(得分:5)
我假设您正在获得具有以下内容的对象大小:
sum(sys.getsizeof(i) for i in gc.get_objects())
请记住gc.get_objects()
的结果不包括解释器本身消耗的内存,只包含垃圾收集器跟踪的Python对象。此外,此函数依赖于从__sizeof__()
方法返回准确结果的对象,因此,如果您使用任何第三方模块,则无法获得准确的结果。
您可能已经这样做了,但是您可以让您的应用程序定期调用gc.collect()
,然后检查gc.garbage
以查看您是否有任何收集器无法释放的无法访问的对象。如果您有任何已覆盖__del__()
的循环引用的类,则会出现这种情况。(请参阅Python docs for gc)。
我还建议将此调用添加到代码的开头:
gc.set_debug(gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_INSTANCES | gc.DEBUG_OBJECTS)
只要找到带有循环引用等的对象,就会将消息打印到stderr
。这可能会为您提供有关何处更密切关注的有用信息。
到目前为止,这些问题很可能已经被objgraph所接受,但是无论如何都可能值得把它们放进去,因为你可以让它们在一个长期运行的守护进程中保持活动状态,以便随时记录这些问题。问题发生了。
如果您正在使用任何C扩展(无论是您自己编写的还是第三方扩展),请仔细检查代码是否存在处理引用计数的错误 - 在那里犯错很容易。另外,请记住,没有什么可以阻止扩展在Python的分配器之外分配自己的内存 - 在这种情况下,如果这些泄漏,你在Python解释器中没有做任何事情就会检测到它。
所有这一切,如果您仍然看到内存使用量单调增加而您找不到任何原因导致的Python对象,那么可能是时候检查较低级别C代码或Python解释器本身的泄漏 - 一个很好的工具是Valgrind。
要在Valgrind中使用Python,您需要使用the Python suppression file。您可能会发现这已经安装 - 例如,Ubuntu会在/usr/lib/valgrind/python.supp
中放置此文件的修改后的形式。
要正确执行此操作,您需要按照Python发行版中的README.valgrind文件中的说明重新编译Python,但即使没有这个,您也可能会发现一些有趣的结果。
有关在this stack overflow question的Valgrind下运行Python的更多讨论。