我如何找到生产系统中Python进程中正在使用内存的内容?

时间:2020-03-06 14:48:06  来源:igfitidea点击:

我的生产系统偶尔会出现内存泄漏,而这是我在开发环境中无法复制的。我在开发环境中使用了Python内存事件探查器(特别是Heapy),但取得了一些成功,但是它无法帮助我解决无法重现的问题,并且我不愿意使用Heapy来检测生产系统,因为它需要花点时间来完成它的工作,并且它的线程化远程接口在我们的服务器中无法正常工作。

我想我想要的是一种转储生产Python进程(或者至少gc.get_objects)快照,然后离线分析快照以查看其在哪里使用内存的方法。我如何获得像这样的python进程的核心转储?一旦有了一个,我该如何做些有用的事情?

解决方案

我不知道如何转储整个python解释器状态并还原它。这将很有用,如果其他人有想法,我会一直关注这个答案。

如果我们知道内存泄漏的位置,则可以添加检查对象的引用计数。例如:

x = SomeObject()
... later ...
oldRefCount = sys.getrefcount( x )
suspiciousFunction( x )
if (oldRefCount != sys.getrefcount(x)):
    print "Possible memory leak..."

我们还可以检查引用计数是否高于对应用程序合理的数量。为了更进一步,我们可以修改python解释器以通过使用自己的Py_INCREFPy_DECREF宏替换这些检查。但是,这在生产应用程序中可能会有些危险。

这是一篇文章,其中提供了有关调试这类事情的更多信息。它更适合于插件作者,但大多数适用。

调试参考计数

gc模块具有一些可能有用的功能,例如列出所有发现垃圾回收器无法访问但无法释放的对象,或者列出所有被跟踪对象的列表。

如果我们怀疑哪些对象可能泄漏,则弱引用模块可以很方便地查找是否/何时收集了对象。

我们能否在生产站点上记录流量(通过日志),然后在配备python内存调试器的开发服务器上重播流量? (我建议使用推土机:http://pypi.python.org/pypi/Dozer)

使程序转储为核心,然后使用gdb在足够相似的框中克隆该程序的实例。有一些特殊的宏可以帮助调试gdb中的python程序,但是如果我们可以让程序同时为远程shell提供服务,则可以继续执行程序,并使用python查询它。

我从来没有做过此事,所以我不是100%确信它会工作,但也许指针会有所帮助。

Meliae看起来很有前途:

This project is similar to heapy (in the 'guppy' project), in its attempt to understand how memory has been allocated.
  
  Currently, its main difference is that it splits the task of computing summary statistics, etc of memory consumption from the actual scanning of memory consumption. It does this, because I often want to figure out what is going on in my process, while my process is consuming huge amounts of memory (1GB, etc). It also allows dramatically simplifying the scanner, as I don't allocate python objects while trying to analyze python object memory consumption.