谁吃了我的Python内存?

时间:2014-03-25 19:19:14

标签: python profiling

关于Python代码的一般性问题。 如何在内存使用方面最有效地找到Python代码中最糟糕的部分?

参见例如这个小例子

def my_func():
    a = [1] * (12 ** 4)
    return a

def my_func2():
    b = [2] * (10 ** 7)
    return b

if __name__ == '__main__':
    a1 = my_func()
    a2 = my_func2()

我怎样才能以自动方式告诉a2比a1大得多? 我怎样才能 - 仍然自动化 - 将其重新导向my_func1()my_func2()

对于C / C ++代码,我会使用valgrind --tool=massif,它可以直接找到关于内存使用的重量级 - 但对于Python我需要你的帮助。 Meliae似乎给出了一些答案,但不及Massif对C / C ++的好处。

1 个答案:

答案 0 :(得分:0)

locals()(resp.globals())返回一个包含所有本地(resp。全局)活动对象的字典。您可以像这样使用它们:

import sys
sizes = dict((obj, sys.getsizeof(eval(obj))) for obj in locals().keys())

缺点是它不会知道没有完全实现__getsizeof__的对象,如Numpy数组或引用。例如,如果你这样做:

print sys.getsizeof(a2)
sys.getsizeof(a1)
a2.append(a1)
print sys.getsizeof(a2)

输出将是:

40000036
   82980
45000064   ---> The list is 60 times bigger!

当然,只是删除a1不会释放它的82 k,因为a1中仍然有一个引用。但我们可以让它变得更奇怪:

a2 = my_func2()
print sys.getsizeof(a2)
a2.append(a2)
print sys.getsizeof(a2)

输出看起来很奇怪:

40000036
45000064

其他工具可能会对此实现变通方法,并搜索引用树,但Python中完整内存分析的一般问题仍未解决。当对象通过C API在参考计数器的范围之外存储数据时,这会变得更糟,例如,与Numpy数组一起发生。

也就是说,对于大多数实际情况,有些工具“足够好”。与引用的链接一样,Heapy是一个非常好的选择。