这是内存泄漏吗? (python + numpy)

时间:2013-06-13 10:51:28

标签: python memory-leaks numpy

以下代码填满了我的所有记忆:

from sys import getsizeof
import numpy

# from http://stackoverflow.com/a/2117379/272471
def getSize(array):
    return getsizeof(array) + len(array) * getsizeof(array[0])


class test():
    def __init__(self):
        pass
    def t(self):
        temp = numpy.zeros([200,100,100])
        A = numpy.zeros([200], dtype = numpy.float64)
        for i in range(200):
            A[i] = numpy.sum( temp[i].diagonal() ) 
        return A

a = test()
memory_usage("before")
c = [a.t() for i in range(100)]
del a
memory_usage("After")
print("Size of c:", float(getSize(c))/1000.0)

输出结果为:

('>', 'before', 'memory:', 20588, 'KiB  ')
('>', 'After', 'memory:', 1583456, 'KiB  ')
('Size of c:', 8.92)

如果c为~9 KiB,为什么我使用~1.5 GB的内存?这是内存泄漏吗? (感谢)

memory_usage功能已发布在SO上,为清晰起见,此处会报告:

def memory_usage(text = ''):
    """Memory usage of the current process in kilobytes."""
    status = None
    result = {'peak': 0, 'rss': 0}
    try:
        # This will only work on systems with a /proc file system
        # (like Linux).
        status = open('/proc/self/status')
        for line in status:
            parts = line.split()
            key = parts[0][2:-1].lower()
            if key in result:
                result[key] = int(parts[1])
    finally:
        if status is not None:
            status.close()
    print('>', text, 'memory:', result['rss'], 'KiB  ')
    return result['rss']

3 个答案:

答案 0 :(得分:5)

问题是由1.7.0版本的numpy的diagonal()函数引起的。 升级到1.7.1解决了这个问题!

该解决方案由塞巴斯蒂安伯格和查尔斯哈里斯提供的numpy邮件列表。

答案 1 :(得分:1)

如果需要一些内存,Python会从操作系统中分配内存。

如果它不再需要它,它可能会或可能不会再次返回。

但是如果它没有返回它,内存将在后续分配中重用。你应该检查一下;但据推测,内存消耗不会再增加。

关于你对内存消耗的估计:正如azorius已经写过的那样,你的temp数组消耗16 MB,而你的A数组消耗大约200 * 8 = 1600字节(内部原因+ 40)。如果您使用其中的100个,则为164000字节(加上列表中的一些)。

除此之外,我没有解释你的内存消耗。

答案 2 :(得分:0)

我认为sys.getsizeof不会返回您期望的内容

你的numpy向量A是64位(8字节) - 所以它占用(至少)

8 * 200 * 100 * 100 * 100 / (2.0**30) = 1.5625 GB

所以至少你应该在100个阵列上使用1.5 GB,最后几百mg是用于索引大numpy数据和100个对象的所有整数

无论numpy数组有多大,似乎sys.getsizeof总是返回80:

sys.getsizeof(np.zeros([200,1000,100])) # return 80
sys.getsizeof(np.zeros([20,100,10])) # return 80

在你的代码中你删除了一个微小的工厂对象,它的方法返回巨大的numpy数组,你将这些巨大的数组存储在一个名为c的列表中。 尝试删除c,那么你应该重新获得大部分RAM