在 python 中查找对象的所有引用的好方法是什么?
我问的原因是看起来我们有“内存泄漏”。我们正在从网络浏览器将图像文件上传到服务器。每次执行此操作时,服务器上的内存使用量都会与刚刚上传的文件的大小成比例地增加。该内存永远不会被 python 垃圾收集释放,所以我认为可能存在指向图像数据的杂散引用,这些数据没有被删除或超出范围,即使在每个请求结束时也是如此。
我认为能够问 python:“哪些引用仍然指向这个内存?”会很好。这样我就可以找出是什么阻止垃圾收集释放它。
目前我们正在 Heroku 服务器上运行 Python 和 Django。
Python 的
gc
模块有几个有用的功能,但听起来 gc.get_referrers()
就是您正在寻找的。这是一个例子:
import gc
def foo():
a = [2, 4, 6]
b = [1, 4, 7]
l = [a, b]
d = dict(a=a)
return l, d
l, d = foo()
r1 = gc.get_referrers(l[0])
r2 = gc.get_referrers(l[1])
print r1
print r2
当我运行它时,我看到以下输出:
[[[2, 4, 6], [1, 4, 7]], {'a': [2, 4, 6]}]
[[[2, 4, 6], [1, 4, 7]]]
您可以看到第一行是
l
和d
,第二行只是l
。
在我的简短实验中,我发现结果并不总是那么干净。例如,驻留字符串和元组的引用来源比您预期的要多。
Python 的标准库有
gc
模块,其中包含垃圾收集器 API。您可能想要拥有的功能之一是
gc.get_objects()
此函数返回垃圾收集器当前跟踪的所有对象的列表。下一步是分析它。
如果您知道要跟踪的对象,可以使用
sys
模块的 getrefcount
功能:
>>> x = object()
>>> sys.getrefcount(x)
2
>>> y = x
>>> sys.getrefcount(x)
3
我写了一个小库来帮助解决这个问题:https://github.com/nfergu/referrers。
它有助于回答“什么持有对该对象的引用?”的问题。通过尝试为对象的每个引用分配一个有意义的名称并返回引用图(包括间接引用)。