在下面的代码中,在迭代c1 = 0和迭代c1 = 60之间,内存使用量大约增加了1G。你能帮我发现泄漏吗?
# M = 1000, N=18000
# data is a pandas dataframe with N rows and M columns (it is already loaded when this code begins).
mymat = np.zeros((M,M,N), dtype=bool)
table = pd.Series(index=data.index, data=np.array(range(N)))
data_std = data.std(axis=1)
for c1 in range(M):
for c2 in range(M):
if c1!=c2:
mymat[c1,c2,list(
table.loc[data.index[data.iloc[:,c1]-data.iloc[:,c2]>data_std]])] = True
答案 0 :(得分:0)
实际上,这似乎根本不是内存泄漏,而是通过优化NumPy或您的操作系统为您提供的。 (就像您的操作系统一样,考虑到原始问题中代码的工作方式也存在特定于操作系统的差异。)
这是简化的example.py
–基本思想是相同的。
import numpy as np
import os
import psutil
process = psutil.Process(os.getpid())
def print_memory(message):
rss = process.memory_info().rss
print(f"{message:30s} {rss // 1024:7d}kb")
M = N = 1000
print_memory('start')
#mymat = np.zeros((M, M, N), dtype=bool)
#mymat = (np.random.random((M, M, N)) > 0.5)
print_memory('generated')
for c1 in range(M):
if c1 % 100 == 0:
print_memory(f'iteration {c1}')
for c2 in range(M):
mymat[c1, c2, [1, 2, 3]] = True
print_memory(f'end')
print(mymat.nbytes, mymat.dtype, mymat.shape)
在启用第一行mymat
(即生成零)的情况下运行此命令即可打印
$ python3 example.py
start 23552kb
generated 23564kb
iteration 0 23564kb
iteration 100 121340kb
iteration 200 218996kb
iteration 300 316652kb
iteration 400 414320kb
iteration 500 511976kb
iteration 600 609632kb
iteration 700 707288kb
iteration 800 804944kb
iteration 900 902600kb
end 1000256kb
1000000000 bool (1000, 1000, 1000)
因此您可以看到,“生成” 1000 x 1000 x 1000阵列实际上并不会占用1 GB的内存。Numpy的nbytes
表示确实如此,但是随着它开始充满非零值数据,就会发生分配。
使用第二个选项运行它,生成随机数据,结果如下:
$ python3 example.py
start 23404kb
generated 1000004kb
iteration 0 1000004kb
iteration 100 1000140kb
iteration 200 1000148kb
iteration 300 1000164kb
iteration 400 1000164kb
iteration 500 1000164kb
iteration 600 1000164kb
iteration 700 1000164kb
iteration 800 1000164kb
iteration 900 1000164kb
end 1000164kb
1000000000 bool (1000, 1000, 1000)
如您所见,所有内存都立即分配,并且在循环过程中发生的很少内存增加实际上是舍入错误,并且可能仅是由于常规GC分配所致。 (np.ones()
具有相同的行为。)
对于原始的1000 * 1000 * 18000数组,如果您实际上需要填充所有数组,最终将需要
>>> np.zeros((1000, 1000, 18000), dtype=bool).nbytes
18000000000
18 GB的内存。 (这也指出了Numpy对于布尔数组没有特定的打包数据类型的事实;每个布尔占用一个字节,而不仅仅是一个字节。这很可能是由于性能原因。)