我正在研究一个涉及使用python读取,处理和写入有时大至几百兆字节的文件的项目。当我尝试处理一些特别大的文件时,程序偶尔会失败。它不会说'记忆错误',但我怀疑这是问题(实际上它没有理由失败')。为什么我的python进程会占用这么多内存?
我一直在测试较小文件上的代码并观察'顶部'来查看内存使用情况是什么样的,它通常会达到60%。顶部说我有4050352k的总内存,所以3.8Gb。
同时我试图跟踪与下面的代码有点蟒蛇本身的内存使用情况(请参阅从yesterday我的问题):
mem = 0
for variable in dir():
variable_ = vars()[variable]
try:
if str(type(variable_))[7:12] == 'numpy':
numpy_ = True
else:
numpy_ = False
except:
numpy_ = False
if numpy_:
mem_ = variable_.nbytes
else:
mem_ = sys.getsizeof(variable)
mem += mem_
print variable+ type: '+str(type(variable_))+' size: '+str(mem_)
print 'Total: '+str(mem)
之前,我运行块我设置的所有变量我不不需要None,关闭所有的文件和图形等等。之后,我使用subprocess.call()来运行下一阶段处理所需的fortran程序。在Fortran程序运行时查看顶部显示fortran程序正在使用〜100%的cpu和〜5%的内存,并且python使用cpu的0%和53%的内存。然而,我的一小段代码告诉我,python中的所有变量加起来只有23Mb,应该是〜0.5%。
那么发生了什么?我不希望这个小片段能给我一个关于内存使用情况的地方,但它应该准确地在几Mb以内?还是仅仅是顶层没有注意到内存已经被放弃了,但是如果有必要的话,其他程序可以使用它?
按照要求,这是使用所有内存的代码的简化部分(file_name.cub是一个ISIS3多维数据集,它是一个包含相同映射的5层(带)的文件,第一层是光谱发光,接下来的4个与纬度,经度和其他细节有关,它是来自Mars想要处理的图像StartByte是我以前从.cub文件的ascii标题读取的值,告诉我开始的字节数据,样品和线条地图,还从报头读取的尺寸):
latitude_array = 'cheese' # It'll make sense in a moment
f_to = open('To_file.dat','w')
f_rad = open('file_name.cub', 'rb')
f_rad.seek(0)
header=struct.unpack('%dc' % (StartByte-1), f_rad.read(StartByte-1))
header = None
#
f_lat = open('file_name.cub', 'rb')
f_lat.seek(0)
header=struct.unpack('%dc' % (StartByte-1), f_lat.read(StartByte-1))
header = None
pre=struct.unpack('%df' % (Samples*Lines), f_lat.read(Samples*Lines*4))
pre = None
#
f_lon = open('file_name.cub', 'rb')
f_lon.seek(0)
header=struct.unpack('%dc' % (StartByte-1), f_lon.read(StartByte-1))
header = None
pre=struct.unpack('%df' % (Samples*Lines*2), f_lon.read(Samples*Lines*2*4))
pre = None
# (And something similar for the other two bands)
# So header and pre are just to get to the right part of the file, and are
# then set to None. I did try using seek(), but it didn't work for some
# reason, and I ended up with this technique.
for line in range(Lines):
sample_rad = struct.unpack('%df' % (Samples), f_rad.read(Samples*4))
sample_rad = np.array(sample_rad)
sample_rad[sample_rad<-3.40282265e+38] = np.nan
# And Similar lines for all bands
# Then some arithmetic operations on some of the arrays
i = 0
for value in sample_rad:
nextline = sample_lat[i]+', '+sample_lon[i]+', '+value # And other stuff
f_to.write(nextline)
i += 1
if radiance_array == 'cheese': # I'd love to know a better way to do this!
radiance_array = sample_rad.reshape(len(sample_rad),1)
else:
radiance_array = np.append(radiance_array, sample_rad.reshape(len(sample_rad),1), axis=1)
# And again, similar operations on all arrays. I end up with 5 output arrays
# with dimensions ~830*4000. For the large files they can reach ~830x20000
f_rad.close()
f_lat.close()
f_to.close() # etc etc
sample_lat = None # etc etc
sample_rad = None # etc etc
#
plt.figure()
plt.imshow(radiance_array)
# I plot all the arrays, for diagnostic reasons
plt.show()
plt.close()
radiance_array = None # etc etc
# I set all arrays apart from one (which I need to identify the
# locations of nan in future) to None
# LOCATION OF MEMORY USAGE MONITOR SNIPPET FROM ABOVE
所以我在有关打开多个文件的意见撒谎,这是同一个文件的多个实例。我只继续使用一个未设置为None的数组,它的大小为〜830x4000,尽管这在某种程度上构成了我可用内存的50%。我也试过gc.collect,但没有改变。我很乐意听到关于如何改进任何代码(关于这个问题或其他方面)的建议。
也许我应该提一下:原本我打开的文件是全部的(即不是像上面那样一行一行地打开),一行一行地完成是最初尝试节省内存。
我在长时间运行的过程中使用numpy时遇到过类似的问题 - 它会像筛子一样泄漏或像堆栈一样碎裂。你是否创建了很多numpy数组并摧毁它们? – 2012-08-03 17:38:13
Python在破坏*某个对象实例之后不会立即将内存释放回系统。它有一些对象池,称为竞技场,需要一段时间才会被释放。在某些情况下,您可能会遭受内存碎片,这也会导致进程的内存使用量增加。 – C2H5OH 2012-08-03 17:38:40
'sys.getsizeof()'不是测试内存使用情况的可靠方法。首先,它只跟踪给定Python对象的内存,而不是它对内存中其他项的引用。其次,根据文档,不能保证为第三方扩展程序正常工作。另外,@ C2H5OH说。 – 2012-08-03 17:40:20