2013-06-13 4 views
2

Следующий код заполняет всю мою память:Это утечка памяти? (Питон + NumPy)

from sys import getsizeof 
import numpy 

# from http://stackoverflow.com/a/2117379/272471 
def getSize(array): 
    return getsizeof(array) + len(array) * getsizeof(array[0]) 


class test(): 
    def __init__(self): 
     pass 
    def t(self): 
     temp = numpy.zeros([200,100,100]) 
     A = numpy.zeros([200], dtype = numpy.float64) 
     for i in range(200): 
      A[i] = numpy.sum(temp[i].diagonal()) 
     return A 

a = test() 
memory_usage("before") 
c = [a.t() for i in range(100)] 
del a 
memory_usage("After") 
print("Size of c:", float(getSize(c))/1000.0) 

Выход есть:

('>', 'before', 'memory:', 20588, 'KiB ') 
('>', 'After', 'memory:', 1583456, 'KiB ') 
('Size of c:', 8.92) 

Почему я использую ~ 1,5 Гб памяти, если с ~ 9 KiB? Это утечка памяти? (Спасибо)

memory_usage функция была размещена на SO и сообщается здесь для ясности:

def memory_usage(text = ''): 
    """Memory usage of the current process in kilobytes.""" 
    status = None 
    result = {'peak': 0, 'rss': 0} 
    try: 
     # This will only work on systems with a /proc file system 
     # (like Linux). 
     status = open('/proc/self/status') 
     for line in status: 
      parts = line.split() 
      key = parts[0][2:-1].lower() 
      if key in result: 
       result[key] = int(parts[1]) 
    finally: 
     if status is not None: 
      status.close() 
    print('>', text, 'memory:', result['rss'], 'KiB ') 
    return result['rss'] 
+0

Замените 'float (getsizeof (c))/1000.0)' с 'float (getSize (c))/1000.0), и вы должны получить лучшее значение. – glglgl

+0

Спасибо glglgl, я на самом деле скопировал неправильную версию моего образца кода. Исправленный. – Pie86

+0

Что произойдет, если вы добавите del temp непосредственно перед оператором return в t()? – reptilicus

ответ

5

Проблема вызвана функцией diagonal() версии 1.7.0 numpy. Обновление до версии 1.7.1 решило проблему!

Решение было предоставлено Себастьяном Бергом и Чарльзом Харрисом из списка рассылки numpy.

+0

+1, приятно, что вы решили! – jcr

+0

Было бы полезно связать с документацией о том, что на самом деле было исправлено. – merv

1

памяти Python ALLOCS от операционной системы, если она нуждается в некоторых.

Если он больше не нужен, он может или не сможет вернуть его снова.

Но если он не возвращает его, память будет использоваться повторно при последующих распределениях. Вы должны это проверить; но, предположительно, потребление памяти не увеличится еще больше.

О ваших оценках потребления памяти: Как уже писал азорий, ваш массив temp потребляет 16 МБ, в то время как ваш массив A потребляет около 200 * 8 = 1600 байт (+ 40 по внутренним причинам). Если вы берете 100 из них, вы находитесь на 164000 байт (плюс некоторые из них).

Кроме того, у меня нет объяснений относительно используемого вами объема памяти.

+0

Это понятно, спасибо. Тем не менее, если я увеличиваю количество раз, когда я вызываю 'a.t()' до 200, мой процесс будет убит ядром. Почему это происходит? Я должен иметь 2 * 9 = 18 KiB использования памяти, не так ли? – Pie86

+0

@ Pie86 проверяет мое сообщение, 200-ти матричные размеры этого размера занимают по крайней мере 3 ГБ пространства, вы не удаляете возвращаемые матрицы, а только крошечный маленький класс, который их создает. – jcr

+0

@azorius это правильно, но я сохраняю только маленькую возвращаемую матрицу. Проблема, как вы предположили, является большой временной матрицей 'temp', которая не удаляется вместе с классом. – Pie86

0

Я не думаю, что sys.getsizeof возвращает то, что вы ожидаете

ваш NumPy вектор А 64 бит (8 байт) - так он занимает (по крайней мере)

8 * 200 * 100 * 100 * 100/(2.0**30) = 1.5625 GB 

так, как минимум, вы должны использовать 1,5 ГБ на 100 массивах, последние несколько сотен мг - это целые числа, используемые для индексирования больших данных о количестве и 100 объектах.

Кажется, что sys.getsizeof всегда возвращает 80 независимо от того, насколько велика массив numpy это:

sys.getsizeof(np.zeros([200,1000,100])) # return 80 
sys.getsizeof(np.zeros([20,100,10])) # return 80 

В коде вы удаляете крошечный заводский объект, метод t возвращает огромные массивы numpy, вы храните эти огромные массивы в списке c. попробуйте удалить c, тогда вы должны восстановить большую часть своей оперативной памяти

+1

'8 * 200 * 100 * 100 = 16000000 B = 15625 kiB = 15.2587890625 MiB', на три порядка меньше, чем вы ожидали. Но это имеет значение только для одного А, у нас их 100. Более старая система может столкнуться с проблемами с этими размерами ... – glglgl

+0

@glglgl да, но 15 МБ * 100 = 1,5 ГБ ... Я был немного, чтобы вызвать счастливый мой пост, поскольку я всегда отправляю сообщение, а затем редактирую ВСЕ ошибки, спасибо за указание на это :) – jcr

+0

1.5GB, справа. Может быть слишком много для старой системы. – glglgl

Смежные вопросы