内存泄漏,gc跟踪的对象大小远小于进程的内存使用量

app*_*orc 0 python garbage-collection memory-leaks

我们的目标是一个大系统.我们知道现在必须有一些内存泄漏.但要找到原因是如此困难.每次进程使用的内存达到千兆字节时,它的响应都很慢.从"顶部"看到的cpu使用率是100%,即使这个过程也没有工作要做.

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

有人能给我们指点吗?谢谢.

Car*_*roo 6

我假设您正在使用以下内容获取对象的大小:

sum(sys.getsizeof(i) for i in gc.get_objects())
Run Code Online (Sandbox Code Playgroud)

请记住,结果gc.get_objects()不包括解释器本身消耗的内存,只包括垃圾收集器跟踪的Python对象.此外,此函数依赖于从其__sizeof__()方法返回准确结果的对象,因此,如果您使用任何第三方模块,那么您不一定能够获得准确的结果.

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

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

gc.set_debug(gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_INSTANCES | gc.DEBUG_OBJECTS)
Run Code Online (Sandbox Code Playgroud)

stderr只要找到带有循环引用等的对象,这就会打印消息.这可能会为您提供有关何处更密切关注的有用信息.

到目前为止,这些问题很可能已经被objgraph所接受,但是无论如何都可能值得把它们放进去,因为你可以让它们在一个长期运行的守护进程中保持活动状态,以便随时记录这些问题.

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

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

要在Valgrind中使用Python,您需要使用Python抑制文件.您可能会发现这已经安装 - 例如,Ubuntu会将此文件的修改后的形式放入其中/usr/lib/valgrind/python.supp.

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

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