Я использую Python 3 и Numpy для анализа некоторых научных данных и столкнулся с проблемой памяти. При циклическом просмотре списка пустых массивов (несколько тысяч из них) и выполнении нескольких промежуточных вычислений я заметил, что python занимает на 6 ГБ больше памяти, чем я ожидал. Я выделил проблему в одну функцию, показанную ниже:
def overlap_correct(self):
running_total = np.zeros((512, 512))
shutter = 0
for data_index in range(len(self.data)):
if self.TOF[data_index] < self.shutter_times[shutter]:
occupied_prob = running_total/self.N_TRIGS[data_index]
running_total += self.data[data_index]
self.data[data_index] = np.round(np.divide(self.data[data_index], (1 - occupied_prob)))
else:
running_total = np.zeros((512, 512))
shutter += 1
Соответствующими структурами данных здесь являются self.data
, представляющий собой список из пяти тысяч 512x512 числовых массивов, self.TOF
и self.N_TRIGS
- это числовые массивы из нескольких тысяч чисел с плавающей запятой, а self.shutter
раз - это числовой массив с три плавания.
Во время обработки этого цикла, которая занимает несколько минут, я могу наблюдать постепенное увеличение использования памяти Python до тех пор, пока цикл не завершится с использованием примерно на 6 ГБ памяти больше, чем при его запуске.
Я использовал memory_profiler
и objgraph
для анализа использования памяти без какого-либо успеха. Мне известно, что до и после цикла self.data
, self.TOF
, self.N_TRIGS
и self.shutter
остаются одинакового размера и содержат одинаковое число и элементы одного типа. Если я правильно понимаю, локальные переменные, такие как occupied _prob
, должны выходить из области видимости после каждой итерации цикла for
, а если нет, то вся избыточная память должна собираться мусором после того, как функция вернется в основной цикл. Этого не происходит, и 6 ГБ остаются заблокированными до завершения сценария. Я также попытался запустить сборку мусора вручную, используя gc.collect()
безрезультатно.
Если это помогает, эта функция существует внутри потока и является частью более крупного процесса анализа данных. Другие потоки не пытаются одновременно получить доступ к данным, и после завершения потока self.data
копируется в другой класс. Экземпляр потока затем уничтожается при выходе из области видимости. Я также попытался вручную уничтожить поток, используя del thread_instance
и thread_instance = None
, но 6 ГБ остаются заблокированными. Это не является большой проблемой на компьютере разработчика, но код будет частью более крупного пакета, который может работать на машинах с ограниченным объемом оперативной памяти.