Как я могу явно освободить память в Python?
Я написал программу Python, которая действует на большой входной файл, чтобы создать несколько миллионов объектов, представляющих треугольники. Алгоритм такой:
- чтение входного файла
- обработайте файл и создайте список треугольников, представленных их вершинами
- вывод вершин в формате OFF: список вершин, за которым следует список треугольников. Треугольники представлены индексами в списке вершин
в требование OFF, что я распечатываю полный список вершин, прежде чем я распечатаю треугольники, означает, что я должен держать список треугольников в памяти, прежде чем записывать вывод в файл. В то же время я получаю ошибки памяти из-за размеров списков.
Как лучше всего сказать Python, что мне больше не нужны некоторые данные, и его можно освободить?
9 ответов:
по данным Официальная Документация Python, вы можете заставить сборщик мусора освободить неиспользуемую память с помощью
gc.collect(). Пример:import gc gc.collect()
к сожалению (в зависимости от вашей версии и выпуска Python) некоторые типы объектов используют "свободные списки", которые являются аккуратной локальной оптимизацией, но могут вызвать фрагментацию памяти, в частности, делая все больше и больше памяти "выделенной" только для объектов определенного типа и тем самым недоступной для "общего фонда".
единственный действительно надежный способ гарантировать, что большое, но временное использование памяти возвращает все ресурсы в систему, когда это будет сделано, - это использовать это происходит в подпроцессе,который выполняет работу с памятью, а затем завершается. В таких условиях операционная система будет выполнять свою работу и с радостью перерабатывать все ресурсы, которые подпроцесс, возможно, сожрал. К счастью,
multiprocessingмодуль делает такую операцию (которая раньше была довольно болезненной) не слишком плохой в современных версиях Python.в вашем случае использования, кажется, что лучший способ для подпроцессов, чтобы накопить некоторые результаты и все же обеспечить эти результаты доступны основной процесс заключается в использовании полу-временные файлы (полу-временном смысле, а не типа файлов, которые автоматически исчезают, когда закрыт, просто обычные файлы, которые вы не удалите, когда вы закончили с ними).
на
delзаявление может быть полезным, но IIRC не гарантируется освобождение памяти. Элемент документы здесь ... и почему он не выходит здесь.Я слышал, что люди в системах Linux и Unix-типа разветвляют процесс python, чтобы выполнить некоторую работу, получить результаты, а затем убить его.
в этой статье есть заметки о сборщике мусора Python, но я думаю отсутствие контроля памяти недостаток управляемой памяти
Python собирает мусор, поэтому, если вы уменьшите размер своего списка, он восстановит память. Вы также можете использовать оператор "del", чтобы полностью избавиться от переменной:
biglist = [blah,blah,blah] #... del biglist
вы не можете явно освобождать память. Что вам нужно сделать, это убедиться, что вы не держите ссылки на объекты. Затем они будут собирать мусор, освобождая память.
в вашем случае, когда вам нужны большие списки, вам обычно нужно реорганизовать код, обычно используя генераторы/итераторы. Таким образом, вам не нужно иметь большие списки в памяти по адресу все.
http://www.prasannatech.net/2009/07/introduction-python-generators.html
(освобождение памяти периодически выполняется автоматически.
delможет быть, таким образом, ваш друг, как он помечает объекты как удалить.)возможно, вы не столкнетесь с какой-либо проблемой памяти в первую очередь, используя более компактную структуру для ваших данных. Таким образом, списки чисел гораздо менее эффективны для памяти, чем формат, используемый стандартом
arrayмодуль или третьих лицnumpyмодуль. Вы бы сохранили память, поместив свои вершины в массив NumPy 3xN и ваш треугольники в N-элементном массиве.
другие опубликовали некоторые способы, которыми вы могли бы "уговорить" интерпретатор Python освободить память (или иначе избежать проблем с памятью). Скорее всего, вы должны попробовать свои идеи в первую очередь. Однако я считаю важным дать вам прямой ответ на ваш вопрос.
там действительно не любой способ, чтобы напрямую сказать Python, чтобы освободить память. Дело в том, что если вы хотите такой низкий уровень контроля, вам придется написать расширение на C или C++.
тем не менее, есть некоторые инструменты, чтобы помочь с этим:
у меня была похожая проблема при чтении графика из файла. Обработка включала вычисление плавающей матрицы 200 000x200 000 (по одной строке за раз), которая не помещалась в память. Попытка освободить память между вычислениями с помощью
gc.collect()исправлен связанный с памятью аспект проблемы, но это привело к проблемам с производительностью: я не знаю, почему, но даже если объем используемой памяти оставался постоянным, каждый новый вызовgc.collect()заняло немного больше времени, чем предыдущий. Так что вполне быстро сбор мусора занял большую часть вычислительного времени.чтобы исправить проблемы с памятью и производительностью, я переключился на использование многопоточного трюка, который я где-то читал (извините, я больше не могу найти соответствующий пост). Прежде чем я читал каждую строку файла в большом
forцикл, обработка его и запускgc.collect()каждый раз и время, чтобы освободить место в памяти. Теперь я вызываю функцию, которая читает и обрабатывает кусок файла в новом потоке. Когда-то поток заканчивается, память автоматически освобождается без странной проблемы производительности.практически это работает так:
from dask import delayed # this module wraps the multithreading def f(storage, index, chunk_size): # the processing function # read the chunk of size chunk_size starting at index in the file # process it using data in storage if needed # append data needed for further computations to storage return storage partial_result = delayed([]) # put into the delayed() the constructor for your data structure # I personally use "delayed(nx.Graph())" since I am creating a networkx Graph chunk_size = 100 # ideally you want this as big as possible while still enabling the computations to fit in memory for index in range(0, len(file), chunk_size): # we indicates to dask that we will want to apply f to the parameters partial_result, index, chunk_size partial_result = delayed(f)(partial_result, index, chunk_size) # no computations are done yet ! # dask will spawn a thread to run f(partial_result, index, chunk_size) once we call partial_result.compute() # passing the previous "partial_result" variable in the parameters assures a chunk will only be processed after the previous one is done # it also allows you to use the results of the processing of the previous chunks in the file if needed # this launches all the computations result = partial_result.compute() # one thread is spawned for each "delayed" one at a time to compute its result # dask then closes the tread, which solves the memory freeing issue # the strange performance issue with gc.collect() is also avoided
Если вы не заботитесь о повторном использовании вершин, у вас может быть два выходных файла-один для вершин и один для треугольников. Затем добавьте файл треугольника в файл вершины, когда вы закончите.
Comments