SLURM Python脚本在循环中积累内存

SLURM Python脚本在循环中积累内存,python,memory-leaks,out-of-memory,slurm,Python,Memory Leaks,Out Of Memory,Slurm,我正在SLURM scheduler for HPC上运行一个简单的python脚本。 它读取一个数据集(约6GB),并打印和保存部分数据的图像。其中有几个数据文件,所以我使用循环进行迭代,直到我从每个文件中绘制完数据 然而,由于某些原因,每个循环中的内存使用量都会增加。我已经使用getsizeof()映射了变量,但它们似乎不会随着迭代而改变。所以我不确定这个内存“泄漏”是从哪里来的 这是我的剧本: import os, psutil import sdf_helper as sh import

我正在SLURM scheduler for HPC上运行一个简单的python脚本。 它读取一个数据集(约6GB),并打印和保存部分数据的图像。其中有几个数据文件,所以我使用循环进行迭代,直到我从每个文件中绘制完数据

然而,由于某些原因,每个循环中的内存使用量都会增加。我已经使用getsizeof()映射了变量,但它们似乎不会随着迭代而改变。所以我不确定这个内存“泄漏”是从哪里来的

这是我的剧本:

import os, psutil
import sdf_helper as sh
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as plticker
plt.rcParams['figure.figsize'] = [6, 4]
plt.rcParams['figure.dpi'] = 120 # 200 e.g. is really fine, but slower
from sys import getsizeof


for i in range(5,372):
    plt.clf()   
    fig, ax = plt.subplots()
    #dd gets data using the epoch specific SDF file reader sh.getdata
    dd = sh.getdata(i,'/dfs6/pub/user');
    #extract density data as 2D array
    den = dd.Derived_Number_Density_electron.data.T;
    nmin = np.min(dd.Derived_Number_Density_electron.data[np.nonzero(dd.Derived_Number_Density_electron.data)])
    #extract grid points as 2D array
    xy = dd.Derived_Number_Density_electron.grid.data
    #extract single number time
    time = dd.Header.get('time')
    #free up memory from dd
    dd = None
    #plotting
    plt.pcolormesh(xy[0], xy[1],np.log10(den), vmin = 20, vmax = 30)
    cbar = plt.colorbar()
    cbar.set_label('Density in log10($m^{-3}$)')
    plt.title("time:   %1.3e s \n Min e- density:   %1.2e $m^{-3}$" %(time,nmin))
    ax.set_facecolor('black')
    plt.savefig('D00%i.png'%i, bbox_inches='tight')
    print("dd: ", getsizeof(dd))
    print("den: ",getsizeof(den))
    print("nmin: ",getsizeof(nmin))
    print("xy: ",getsizeof(xy))
    print("time: ",getsizeof(time))
    print("fig: ",getsizeof(fig))
    print("ax: ",getsizeof(ax))
    process = psutil.Process(os.getpid())
    print(process.memory_info().rss)
输出

Reading file /dfs6/pub/user/0005.sdf
dd:  16
den:  112
nmin:  32
xy:  56
time:  24
fig:  48
ax:  48
8991707136

Reading file /dfs6/pub/user0006.sdf
dd:  16
den:  112
nmin:  32
xy:  56
time:  24
fig:  48
ax:  48
13814497280

Reading file /dfs6/pub/user/0007.sdf
dd:  16
den:  112
nmin:  32
xy:  56
time:  24
fig:  48
ax:  48
18648313856
#!/bin/bash

#SBATCH -p free
#SBATCH --job-name=epochpyd1
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --mem-per-cpu=20000


#SBATCH --mail-type=begin,end
#SBATCH --mail-user=**

module purge
module load python/3.8.0

python3 -u /data/homezvol0/user/CNTDensity.py > density.out
/data/homezvol0/user/CNTDensity.py:21: RuntimeWarning: divide by zero encountered in log10
  plt.pcolormesh(xy[0], xy[1],np.log10(den), vmin = 20, vmax = 30)
/export/spool/slurm/slurmd.spool/job1910549/slurm_script: line 16:  8004 Killed                  python3 -u /data/homezvol0/user/CNTDensity.py > density.out
slurmstepd: error: Detected 1 oom-kill event(s) in step 1910549.batch cgroup. Some of your processes may have been killed by the cgroup out-of-memory handler.
SLURM输入

Reading file /dfs6/pub/user/0005.sdf
dd:  16
den:  112
nmin:  32
xy:  56
time:  24
fig:  48
ax:  48
8991707136

Reading file /dfs6/pub/user0006.sdf
dd:  16
den:  112
nmin:  32
xy:  56
time:  24
fig:  48
ax:  48
13814497280

Reading file /dfs6/pub/user/0007.sdf
dd:  16
den:  112
nmin:  32
xy:  56
time:  24
fig:  48
ax:  48
18648313856
#!/bin/bash

#SBATCH -p free
#SBATCH --job-name=epochpyd1
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --mem-per-cpu=20000


#SBATCH --mail-type=begin,end
#SBATCH --mail-user=**

module purge
module load python/3.8.0

python3 -u /data/homezvol0/user/CNTDensity.py > density.out
/data/homezvol0/user/CNTDensity.py:21: RuntimeWarning: divide by zero encountered in log10
  plt.pcolormesh(xy[0], xy[1],np.log10(den), vmin = 20, vmax = 30)
/export/spool/slurm/slurmd.spool/job1910549/slurm_script: line 16:  8004 Killed                  python3 -u /data/homezvol0/user/CNTDensity.py > density.out
slurmstepd: error: Detected 1 oom-kill event(s) in step 1910549.batch cgroup. Some of your processes may have been killed by the cgroup out-of-memory handler.
SLURM输出

Reading file /dfs6/pub/user/0005.sdf
dd:  16
den:  112
nmin:  32
xy:  56
time:  24
fig:  48
ax:  48
8991707136

Reading file /dfs6/pub/user0006.sdf
dd:  16
den:  112
nmin:  32
xy:  56
time:  24
fig:  48
ax:  48
13814497280

Reading file /dfs6/pub/user/0007.sdf
dd:  16
den:  112
nmin:  32
xy:  56
time:  24
fig:  48
ax:  48
18648313856
#!/bin/bash

#SBATCH -p free
#SBATCH --job-name=epochpyd1
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --mem-per-cpu=20000


#SBATCH --mail-type=begin,end
#SBATCH --mail-user=**

module purge
module load python/3.8.0

python3 -u /data/homezvol0/user/CNTDensity.py > density.out
/data/homezvol0/user/CNTDensity.py:21: RuntimeWarning: divide by zero encountered in log10
  plt.pcolormesh(xy[0], xy[1],np.log10(den), vmin = 20, vmax = 30)
/export/spool/slurm/slurmd.spool/job1910549/slurm_script: line 16:  8004 Killed                  python3 -u /data/homezvol0/user/CNTDensity.py > density.out
slurmstepd: error: Detected 1 oom-kill event(s) in step 1910549.batch cgroup. Some of your processes may have been killed by the cgroup out-of-memory handler.
据我所知,一切似乎都在运转。不确定什么会占用超过20GB的内存

编辑 所以我开始从下到上注释循环的各个部分。现在很明显,普科洛梅什是罪魁祸首

我添加了():


直到最后,但无论发生什么,记忆都在不断攀升。我完全不知道发生了什么事。

您走的是正确的道路,可以看到每次迭代累积了多少内存。调试的下一步是想一想这些记忆可能在哪里积累的假设,以及测试这些假设的方法

每次迭代后,一个保持在内存中的变量是
den
。您可以排除这些假设(从而缩小问题范围),方法是通过
dd=None
清除这些变量,或者通过
del dd
删除它们,或者将循环体的一部分移动到子例程中,这样当这些子例程返回时,一些变量就会消失。(分解出子例程也可以使这些部分更易于重用和测试。)这种技术可以排除问题的一些可能原因,但我不希望这些变量赋值在迭代过程中积累内存,如果代码在每次迭代时向
dict
列表添加数据,就会积累内存

另一个假设是,
matplotlib
中的状态累积未被
plt.clf()
清除,或者在
sdf\u helper
中的状态累积。我对这些库了解不够,无法提供直接的见解,但它们的文档应该说明如何清除状态。即使不知道如何弄清它们的状态,我们也可以想出方法来检验这些假设。例如,注释掉
plt
调用或至少注释掉数据密集型调用,然后查看内存是否仍在累积

你可能会想到比我更多的假设。首先头脑风暴假设是一种很好的方法,因为其中一个假设可能是明显的最佳候选,或者其中一个假设可能比其他假设更容易测试

请注意,积累内存可能有多个原因,在这种情况下,修复一个原因将减少内存积累,但无法修复它。因为你在测量记忆积累,你就能检测到这一点。在许多调试情况下,我们看不到多个原因对问题(如片状结果)的增量贡献,因此另一种方法是删除所有可能导致问题的原因,然后一次添加一个

添加内容

现在您已经将问题缩小到
pcolormesh
,下一步是阅读有关matplotlib和
pcolormesh
如何使用内存的or教程。此外,通过web搜索
pcolormesh内存泄漏
可以找到有关此问题的特定提示

最简单的尝试是添加对
ax.cla()
的调用以清除轴,如中所示

您可以从pyplot切换到matplotlib的面向对象接口,该接口不会保留太多全局状态。相反,我认为
pyplot
保留了
fig
ax
,在这种情况下,释放变量不足以释放它们的对象

显然
imshow


请注意,其中建议只创建一次
pcolormesh
,然后在每次循环迭代中设置其数据——您可以在每次迭代中执行
mesh=plt.pcolormesh(…)
一次,然后执行类似
mesh.set\u数组(np.log10(den))
的操作吗?它还建议您致电
cla()

感谢您的回复!我做了一些编辑。看来普科洛梅什是罪魁祸首。我尝试了其他方法来删除或释放该图(),但内存保持不变climing@ddwong我通过网络搜索和查看Matplotlib文档,添加了一些关于pcolormesh内存保留的注释。你可能需要比我更深入地研究那些文档。