在循环中使用numpy加载时内存溢出

时间:2012-02-11 21:56:37

标签: python memory numpy overflow memory-leaks

循环npz文件加载会导致内存溢出(取决于文件  列表长度)。

以下任何一项似乎都没有帮助

  1. 删除将数据存储在文件中的变量。

  2. 使用mmap。

  3. 调用gc.collect()(垃圾回收)。

  4. 以下代码应该重现这一现象:

    import numpy as np
    
    # generate a file for the demo
    X = np.random.randn(1000,1000)
    np.savez('tmp.npz',X=X)
    
    
    # here come the overflow:
    for i in xrange(1000000):
        data = np.load('tmp.npz')
        data.close()  # avoid the "too many files are open" error
    

    在我的实际应用程序中,循环遍历文件列表,溢出超过24GB的RAM!  请注意,这是在ubuntu 11.10和numpy v上尝试过的  1.5.1以及1.6.0

    我已经在numpy ticket 2048提交了一份报告,但这可能会引起更广泛的兴趣,所以我也在这里发布它(此外,我不确定这是一个错误,但可能是由于我编程错误)。

    解决方案(由HYRY提供):

    命令

    del data.f
    

    应该在命令

    之前
    data.close()
    

    有关更多信息和查找解决方案的方法,请阅读下面的HYRY的答案

2 个答案:

答案 0 :(得分:3)

我认为这是一个错误,也许我找到了解决方案:调用“del data.f”。

for i in xrange(10000000):
    data = np.load('tmp.npz')
    del data.f
    data.close()  # avoid the "too many files are open" error

发现这种内存泄漏。您可以使用以下代码:

import numpy as np
import gc
# here come the overflow:
for i in xrange(10000):
    data = np.load('tmp.npz')
    data.close()  # avoid the "too many files are open" error

d = dict()
for o in gc.get_objects():
    name = type(o).__name__
    if name not in d:
        d[name] = 1
    else:
        d[name] += 1

items = d.items()
items.sort(key=lambda x:x[1])
for key, value in items:
    print key, value

在测试程序之后,我在gc.get_objects()中创建了一个dict和count对象。这是输出:

...
wrapper_descriptor 1382
function 2330
tuple 9117
BagObj 10000
NpzFile 10000
list 20288
dict 21001

从结果我们知道BagObj和NpzFile有问题。找到代码:

class NpzFile(object):
    def __init__(self, fid, own_fid=False):
        ...
        self.zip = _zip
        self.f = BagObj(self)
        if own_fid:
            self.fid = fid
        else:
            self.fid = None

    def close(self):
        """
        Close the file.

        """
        if self.zip is not None:
            self.zip.close()
            self.zip = None
        if self.fid is not None:
            self.fid.close()
            self.fid = None

    def __del__(self):
        self.close()

class BagObj(object):
    def __init__(self, obj):
        self._obj = obj
    def __getattribute__(self, key):
        try:
            return object.__getattribute__(self, '_obj')[key]
        except KeyError:
            raise AttributeError, key

NpzFile有 del (),NpzFile.f是BagObj,而BagObj._obj是NpzFile,这是一个参考周期,会导致NpzFile和BagObj无法收集。以下是Python文档中的一些解释:http://docs.python.org/library/gc.html#gc.garbage

因此,要打破引用周期,需要调用“del data.f”

答案 1 :(得分:0)

我发现的解决方案:(python==3.8 和 numpy==1.18.5)

import gc # import garbage collector interface

for i in range(1000):
   data = np.load('tmp.npy')

   # process data

   del data
   gc.collect()