2014-12-01 31 views
0

我有一個python腳本正在處理大量來自壓縮的ASCII數據。經過一段時間後,它會耗盡內存。我沒有構建大型列表或者字典。下面的代碼說明問題:Python內存泄漏使用binascii,zlib,結構和numpy

import struct 
import zlib 
import binascii 
import numpy as np 
import psutil 
import os 
import gc 

process = psutil.Process(os.getpid()) 
n = 1000000 
compressed_data = binascii.b2a_base64(bytearray(zlib.compress(struct.pack('%dB' % n, *np.random.random(n))))).rstrip() 

print 'Memory before entering the loop is %d MB' % (process.get_memory_info()[0]/float(2 ** 20)) 
for i in xrange(2): 
    print 'Memory before iteration %d is %d MB' % (i, process.get_memory_info()[0]/float(2 ** 20)) 
    byte_array = zlib.decompress(binascii.a2b_base64(compressed_data)) 
    a = np.array(struct.unpack('%dB' % (len(byte_array)), byte_array)) 
    gc.collect() 
gc.collect() 
print 'Memory after last iteration is %d MB' % (process.get_memory_info()[0]/float(2 ** 20)) 

它打印:

Memory before entering the loop is 45 MB 
Memory before iteration 0 is 45 MB 
Memory before iteration 1 is 51 MB 
Memory after last iteration is 51 MB 

第一和第二次迭代之間,獲得創建6 MB的內存。如果我運行循環兩次以上,內存使用率保持在51 MB。如果我將代碼解壓縮到自己的函數中,並將實際的壓縮數據提供給它,內存使用量將繼續增長。我正在使用Python 2.7。爲什麼記憶力在​​增加,如何糾正?謝謝。

+0

我不會說,那是內存泄漏,這是正常的內存消耗。 – Daniel 2014-12-01 20:47:19

+0

除了看起來很正常,就像@Daniel說的那樣,'byte_array'和'a = np.array'怎麼樣?在實例化它們之前,您的第一次迭代會輸出內存使用情況*。這聽起來像很多數據,這可能不會被垃圾收集器破壞,因爲你在'for'循環範圍內調用它。 Unindent(向左移動)表示'gc。collect()'所以它在'for'循環之外運行,看看會發生什麼。 – BorrajaX 2014-12-01 20:49:55

+0

@BorrajaX在最後一次打印之前和循環退出之後添加了另一個gc.collect,沒有任何變化。對於所有打印語句,byte_array和「a」變量不應該存在於內存中 – user2133814 2014-12-01 20:55:04

回答

1

通過的意見,我們想通了事情的原委:

的主要問題是,在一個for循環聲明的變量,一旦循環結束不被破壞。他們仍然可以訪問,指着他們在最後一次迭代接收到的值:

>>> for i in range(5): 
...  a=i 
... 
>>> print a 
4 

所以這裏發生的事情:

  • 第一次迭代:該print是顯示45MB,它的內存實例byte_array前和a
  • 代碼實例化這兩個冗長的變量,使內存變爲51MB第二次迭代:循環第一次運行時實例化的兩個變量仍然存在。
  • 在第二次迭代的中間,byte_arraya被新實例覆蓋。最初的那些被破壞,但被同樣冗長的變量所取代。
  • for循環結束,但byte_arraya仍然可以在代碼中訪問,因此,不會由第二個gc.collect()調用破壞。

改變代碼:

for i in xrange(2): 
    [ . . . ] 
byte_array = None 
a = None 
gc.collect() 

由通過byte_arraya不可訪問resreved存儲器中,並且因此,被釋放。

還有更多Python的垃圾收集在這個蘇答案:https://stackoverflow.com/a/4484312/289011

而且,它可能是值得考慮的How do I determine the size of an object in Python?。這很棘手,但是...如果你的對象是一個指向其他對象的列表,的大小是多少?列表中指針的總和?這些指針指向的對象大小的總和?