我正在研究一個涉及使用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