我有一个 Python 进程,在很长一段时间(至少 10 小时,有时更长)后开始泄漏内存。这个问题很难重现,因此我想在问题出现时附加到正在运行的 Python 解释器,并以某种方式检查内存使用情况,例如通过获取当前分配最多内存的对象列表。
使用tracemalloc或memory-profiler等常用分析工具很难做到这一点,因为它们需要成为代码的一部分或与进程一起启动,并且它们对运行时性能有重大影响。
我想要的是一个采样分析器,我可以简单地将其附加到现有的 Python 进程(如 py-spy),但 py-spy 只能让我了解函数中花费的 CPU 时间,而不是内存使用情况。
是否有其他工具或不同的方法可以帮助我深入了解现有 Python 进程的内存使用情况?
edit:我刚刚找到了pyrasite,它提供了pyrasite-memory-viewer命令,这正是我正在寻找的,但不幸的是该项目似乎已被放弃,我无法获取它可以在 Python 3.8 上运行。
https://github.com/vmware/chap(开源代码)可以满足您在此处的请求,只要您可以在 Linux 上运行您的应用程序。
echo 0x37 >/proc/
你的Python程序的pid/coredump_filter
gcore你的Python程序的pid
重定向至
描述使用过的
Anchored allocation at 7f5e7bf2a570 of size 40
This allocation matches pattern ContainerPythonObject.
This has a PyGC_Head at the start so the real PyObject is at offset 0x18.
This has reference count 1 and python type 0x7f5e824c08a0 (dict)
Anchored allocation at 7f5e7bf2a5b0 of size 40
This allocation matches pattern SimplePythonObject.
This has reference count 3 and python type 0x7f5e824cdfe0 (str)
This has a string of length 12 containing
"ETOOMANYREFS".
您可以使用章节中的其他命令来理解为什么您感兴趣的任何分配都被锚定,基本上是因为它们允许您通过传入引用向后遍历,但是上面的命令应该足以让您弄清楚哪些类型的分配有高计数。例如,假设您想了解如何引用 0x7f5e7bf2a570 分配中的字典。你可以执行这个命令:
chap> describe incoming 7f5e7bf2a570 /skipUnfavoredReferences true
Anchored allocation at 17fda90 of size 1a8
This allocation matches pattern PyDictKeysObject.
1 allocations use 0x1a8 (424) bytes.
您可以反过来问 PyDictKeysObject 的引用是什么(不是 python 类型,但用于存储字典的键)
chap> describe incoming 17fda90 /skipUnfavoredReferences true
Anchored allocation at 7f5e7c0e01f0 of size 40
This allocation matches pattern ContainerPythonObject.
The garbage collector considers this allocation to be reachable.
This has a PyGC_Head at the start so the real PyObject is at offset 0x18.
This has reference count 1 and python type 0x7f5e824c08a0 (dict)
1 allocations use 0x40 (64) bytes.
memray attach 选项就是您可能正在寻找的。
确保在将 memray
附加到进程之前安装了 lldb 或 gdb。