Я написал программу на Python, которая работает с большим входным файлом, создавая несколько миллионов объектов, представляющих треугольники. Алгоритм:
- читать входной файл
- обработать файл и создать список треугольников, представленных их вершинами
- Выведите вершины в формате OFF: список вершин, за которым следует список треугольников. Треугольники представлены индексами в списке вершин
Требование OFF, чтобы я распечатывал полный список вершин перед тем, как распечатать треугольники, означает, что я должен держать список треугольников в памяти, прежде чем записать вывод в файл. В то же время я получаю ошибки памяти из-за размеров списков.
Как лучше всего сказать Python, что мне больше не нужны некоторые данные, и их можно освободить?
python
memory
memory-management
Натан Феллман
источник
источник
Ответы:
В соответствии с официальной документацией Python вы можете заставить сборщик мусора освобождать память, на которую нет ссылок
gc.collect()
. Пример:источник
gc.collect()
себя в конце цикла может помочь избежать фрагментации памяти, что, в свою очередь, помогает поддерживать производительность. Я видел, как это существенноgc.collect()
после загрузки кадра данных pandas из hdf5 (500 тыс. Строк) уменьшил использование памяти с 1,7 ГБ до 500 МБdel my_array
последующимgc.collect()
после обработки массивом является единственным способом, которым память фактически освобождается, и мой процесс выживает, чтобы загрузить следующий массив.К сожалению (в зависимости от вашей версии и выпуска Python) некоторые типы объектов используют «свободные списки», которые представляют собой аккуратную локальную оптимизацию, но могут вызвать фрагментацию памяти, в частности, делая все больше и больше памяти «выделенными» только для объектов определенного типа и тем самым недоступен «общему фонду».
Единственный действительно надежный способ гарантировать, что большое, но временное использование памяти ДОЛЖНО возвращать все ресурсы системе, когда это будет сделано, состоит в том, чтобы такое использование происходило в подпроцессе, который выполняет работу, требующую памяти, а затем завершается. В таких условиях операционная система выполнит свою работу и с удовольствием утилизирует все ресурсы, которые подпроцесс мог поглотить. К счастью,
multiprocessing
модуль делает такую операцию (которая раньше была довольно болезненной) не слишком плохой в современных версиях Python.В вашем случае использования кажется, что лучший способ для подпроцессов накапливать некоторые результаты и при этом гарантировать, что эти результаты доступны для основного процесса, - это использовать временные файлы (я имею в виду под временными, а НЕ файлы, которые автоматически уходить при закрытии, просто обычные файлы, которые вы явно удаляете, когда все с ними закончено).
источник
multiprocessing.Manager
вместо файлов для реализации общего состояния.Это
del
заявление может быть полезным, но IIRC не гарантирует освобождение памяти . Эти документы здесь ... и почему он не избавлен здесь .Я слышал, как люди в системах Linux и Unix разрабатывают процесс Python, чтобы выполнить некоторую работу, получить результаты и затем убить их.
В этой статье есть заметки о сборщике мусора Python, но я думаю, что недостаток контроля памяти является недостатком управляемой памяти
источник
Python собирает мусор, поэтому, если вы уменьшите размер списка, он освободит память. Вы также можете использовать оператор "del", чтобы полностью избавиться от переменной:
источник
Вы не можете явно освободить память. Вам нужно убедиться, что вы не храните ссылки на объекты. Затем они будут собирать мусор, освобождая память.
В вашем случае, когда вам нужны большие списки, вам, как правило, нужно реорганизовать код, обычно используя вместо этого генераторы / итераторы. Таким образом, вам не нужно иметь большие списки в памяти вообще.
http://www.prasannatech.net/2009/07/introduction-python-generators.html
источник
(
del
может быть вашим другом, так как он помечает объекты как удаляемые, когда на них нет других ссылок. Теперь часто интерпретатор CPython сохраняет эту память для дальнейшего использования, поэтому ваша операционная система может не видеть «освобожденную» память.)Возможно, вы не столкнетесь с какими-либо проблемами с памятью, если будете использовать более компактную структуру для ваших данных. Таким образом, списки чисел намного менее эффективны по памяти, чем формат, используемый стандартным
array
модулем или стороннимnumpy
модулем. Вы бы сэкономили память, поместив свои вершины в массив NumPy 3xN, а треугольники в массив N-элементов.источник
del
не делает ничего, что просто переназначает другое значение всем именам, ссылающимся на объект, не будет.del
освобождает память с точки зрения Python, но, как правило, не с точки зрения библиотеки времени выполнения C или ОС. Ссылки: stackoverflow.com/a/32167625/4297 , effbot.org/pyfaq/… .del
одинаково эффективен с выходами из области, переназначениями и т. Д.У меня была похожая проблема при чтении графика из файла. Обработка включала вычисление матрицы с плавающей запятой 200 000x200 000 (по одной строке за раз), которая не помещалась в память. Попытка освободить память между вычислениями с помощью
gc.collect()
исправила связанный с памятью аспект проблемы, но это привело к проблемам с производительностью: я не знаю, почему, хотя объем используемой памяти оставался постоянным, каждый новый вызовgc.collect()
занимал немного больше времени, чем предыдущий. Так что довольно быстро сборка мусора заняла большую часть времени вычислений.Чтобы исправить проблемы с памятью и производительностью, я переключился на использование многопоточного трюка, который я однажды где-то читал (извините, я больше не могу найти соответствующий пост). До того, как я прочитал каждую строку файла в большом
for
цикле, обработал его и запускалgc.collect()
время от времени, чтобы освободить место в памяти. Теперь я вызываю функцию, которая читает и обрабатывает кусок файла в новом потоке. Как только поток заканчивается, память автоматически освобождается без странной проблемы с производительностью.Практически это работает так:
источник
Другие опубликовали некоторые способы, которыми вы могли бы «уговорить» интерпретатор Python освободить память (или иначе избежать проблем с памятью). Скорее всего, вы должны попробовать их идеи в первую очередь. Тем не менее, я считаю важным дать вам прямой ответ на ваш вопрос.
На самом деле нет никакого способа напрямую сказать Python освободить память. Дело в том, что если вам нужен такой низкий уровень контроля, вам придется написать расширение на C или C ++.
Тем не менее, есть несколько инструментов, которые помогут с этим:
источник
Если вас не волнует повторное использование вершин, у вас может быть два выходных файла - один для вершин и один для треугольников. Затем добавьте файл треугольника в файл вершин, когда вы закончите.
источник