Пытаясь точно настроить некоторые утечки памяти в привязках Python для некоторых функций C/C++, я столкнулся с некоторым странным поведением, связанным со сборкой мусора из массивов Numpy.
Я создал пару упрощенных случаев, чтобы лучше объяснить поведение. Код был запущен с использованием memory_profiler
, вывод которого следует сразу после него. Похоже, что сборка мусора Python не работает должным образом, когда дело доходит до массивов NumPy:
# File deallocate_ndarray.py
@profile
def ndarray_deletion():
import numpy as np
from gc import collect
buf = 'abcdefghijklmnopqrstuvwxyz' * 10000
arr = np.frombuffer(buf)
del arr
del buf
collect()
y = [i**2 for i in xrange(10000)]
del y
collect()
if __name__=='__main__':
ndarray_deletion()
С помощью следующей команды я вызвал memory_profiler
:
python -m memory_profiler deallocate_ndarray.py
Вот что я получил:
Filename: deallocate_ndarray.py
Line # Mem usage Increment Line Contents
================================================
5 10.379 MiB 0.000 MiB @profile
6 def ndarray_deletion():
7 17.746 MiB 7.367 MiB import numpy as np
8 17.746 MiB 0.000 MiB from gc import collect
9 17.996 MiB 0.250 MiB buf = 'abcdefghijklmnopqrstuvwxyz' * 10000
10 18.004 MiB 0.008 MiB arr = np.frombuffer(buf)
11 18.004 MiB 0.000 MiB del arr
12 18.004 MiB 0.000 MiB del buf
13 18.004 MiB 0.000 MiB collect()
14 18.359 MiB 0.355 MiB y = [i**2 for i in xrange(10000)]
15 18.359 MiB 0.000 MiB del y
16 18.359 MiB 0.000 MiB collect()
Я не понимаю, почему даже принудительные вызовы collect
не уменьшают использование памяти программой, освобождая часть памяти. Более того, даже если массивы Numpy не ведут себя нормально из-за лежащих в их основе конструкций C, почему список (который является чистым Python) не собирает мусор?
Я знаю, что del
не вызывает напрямую базовый метод __del__
, но вы заметите, что все операторы del
в коде фактически приводят к уменьшению счетчика ссылок соответствующих объектов до нуля (таким образом, AFAIK делает их подходящими для сборки мусора). Как правило, я ожидаю увидеть отрицательную запись в столбце приращения, когда объект подвергается сборке мусора. Кто-нибудь может пролить свет на то, что здесь происходит?
ПРИМЕЧАНИЕ. Этот тест выполнялся в OS X 10.10.4, Python 2.7.10 (conda), Numpy 1.9.2 (conda), Memory Profiler 0,33 (conda-binstar), psutil 2.2.1 (conda).