Сократите использование памяти при нарезке пустых массивов - PullRequest
0 голосов
/ 06 мая 2018

У меня проблемы с освобождением памяти в Python. Ситуация в основном такая: у меня большой набор данных, разбитый на 4 файла. Каждый файл содержит список из 5000 массивов фигур (3072, 412). Я пытаюсь извлечь, скажем, 10-20 столбцы каждого массива в новый список.

Я хотел бы последовательно прочитать каждый файл, извлечь нужные мне данные и освободить память, которую я использую, прежде чем перейти к следующему. Однако удаление объекта, установка его на None и установка его на 0 с последующим вызовом gc.collect(), похоже, не работает. Вот фрагмент кода, с которым я работаю:

num_files=4
start=10
end=20           
fields = []
for j in range(num_files):
    print("Working on file ", j)
    source_filename = base_filename + str(j) + ".pkl"
    print("Memory before: ", psutil.virtual_memory())
    partial_db = joblib.load(source_filename)
    print("GC tracking for partial_db is ",gc.is_tracked(partial_db))
    print("Memory after loading partial_db:",psutil.virtual_memory())
    for x in partial_db:
        fields.append(x[:,start:end])
    print("Memory after appending to fields: ",psutil.virtual_memory())
    print("GC Counts before del: ", gc.get_count())
    partial_db = None
    print("GC Counts after del: ", gc.get_count())
    gc.collect()
    print("GC Counts after collection: ", gc.get_count())
    print("Memory after freeing partial_db: ", psutil.virtual_memory())

и вот вывод после пары файлов:

Working on file  0
Memory before:  svmem(total=67509161984, available=66177449984,percent=2.0, used=846712832, free=33569669120, active=27423051776, inactive=5678043136, buffers=22843392, cached=33069936640, shared=15945728)
GC tracking for partial_db is  True
Memory after loading partial_db:  svmem(total=67509161984, available=40785944576, percent=39.6, used=26238181376, free=8014237696, active=54070542336, inactive=4540620800, buffers=22892544, cached=33233850368, shared=15945728)
Memory after appending to fields:  svmem(total=67509161984, available=40785944576, percent=39.6, used=26238181376, free=8014237696, active=54070542336, inactive=4540620800, buffers=22892544, cached=33233850368, shared=15945728)
GC Counts before del:  (0, 7, 3)
GC Counts after del:  (0, 7, 3)
GC Counts after collection:  (0, 0, 0)
Memory after freeing partial_db:  svmem(total=67509161984, available=40785944576, percent=39.6, used=26238181376, free=8014237696, active=54070542336, inactive=4540620800, buffers=22892544, cached=33233850368, shared=15945728)
Working on file  1
Memory before:  svmem(total=67509161984, available=40785944576, percent=39.6, used=26238181376, free=8014237696, active=54070542336, inactive=4540620800, buffers=22892544, cached=33233850368, shared=15945728)
GC tracking for partial_db is  True
Memory after loading partial_db:  svmem(total=67509161984, available=15378006016, percent=77.2, used=51626561536, free=265465856, active=62507155456, inactive=3761905664, buffers=10330112, cached=15606804480, shared=15945728)
Memory after appending to fields:  svmem(total=67509161984, available=15378006016, percent=77.2, used=51626561536, free=265465856, active=62507155456, inactive=3761905664, buffers=10330112, cached=15606804480, shared=15945728)
GC Counts before del:  (0, 4, 2)
GC Counts after del:  (0, 4, 2)
GC Counts after collection:  (0, 0, 0)
Memory after freeing partial_db:  svmem(total=67509161984, available=15378006016, percent=77.2, used=51626561536, free=265465856, active=62507155456, inactive=3761905664, buffers=10330112, cached=15606804480, shared=15945728)

Если я продолжу его отпускать, он израсходует всю память и вызовет исключение MemoryError.

Кто-нибудь знает, что я могу сделать, чтобы обеспечить освобождение данных, используемых partial_db?

1 Ответ

0 голосов
/ 06 мая 2018

Проблема заключается в следующем:

for x in partial_db:
    fields.append(x[:,start:end])

Причина, по которой нарезка пустых массивов (в отличие от обычных списков Python) практически не занимает времени и не тратит впустую пространство, заключается в том, что он не делает копию, он просто создает другое представление в памяти массива. Обычно это здорово. Но здесь это означает, что вы сохраняете память для x живой даже после того, как вы выпустили x, потому что вы никогда не выпускаете эти нарезанные фрагменты.

Есть и другие способы обойти это, но самое простое - просто добавить копии срезов:

for x in partial_db:
    fields.append(x[:,start:end].copy())
...