Отпустить выделенную память сервера Flask [duplicate]

Источником проблемы является то, что объект, возвращаемый из UDF, не соответствует объявленному типу. np.unique не только возвращает numpy.ndarray, но и преобразует числовые значения в соответствующие NumPy типы , которые не совместимы с DataFrame API. Вы можете попробовать что-то вроде этого:

udf(lambda x: list(set(x)), ArrayType(IntegerType()))

или это (чтобы сохранить порядок)

udf(lambda xs: list(OrderedDict((x, None) for x in xs)), 
    ArrayType(IntegerType()))

.

Если вы действительно хотите np.unique вам нужно преобразовать вывод:

udf(lambda x: np.unique(x).tolist(), ArrayType(IntegerType()))

98
задан Jared 19 March 2013 в 08:29
поделиться

2 ответа

Память, выделенная на куче, может быть подвергнута воздействию водяных знаков. Это осложняется внутренней оптимизацией Python для выделения небольших объектов (PyObject_Malloc) в 4 пулах KiB, классифицированных для размеров размещения в кратных 8 байтах - до 256 байт (512 байт в 3.3). Сами пулы находятся в 256 KiB аренах, поэтому, если используется только один блок в одном пуле, вся 256 игровая зона KiB не будет выпущена. В Python 3.3 распределитель малых объектов был переключен на использование анонимных карт памяти вместо кучи, поэтому он должен лучше работать при освобождении памяти.

Кроме того, встроенные типы поддерживают фрилистов ранее выделенных объектов, которые могут или не может использовать распределитель малых объектов. Тип int поддерживает freelist с собственной выделенной памятью, и для его очистки требуется вызвать PyInt_ClearFreeList(). Это можно косвенно назвать полным gc.collect.

Попробуй так, и скажи мне, что получишь. Вот ссылка на psutil .

import os
import gc
import psutil

proc = psutil.Process(os.getpid())
gc.collect()
mem0 = proc.get_memory_info().rss

# create approx. 10**7 int objects and pointers
foo = ['abc' for x in range(10**7)]
mem1 = proc.get_memory_info().rss

# unreference, including x == 9999999
del foo, x
mem2 = proc.get_memory_info().rss

# collect() calls PyInt_ClearFreeList()
# or use ctypes: pythonapi.PyInt_ClearFreeList()
gc.collect()
mem3 = proc.get_memory_info().rss

pd = lambda x2, x1: 100.0 * (x2 - x1) / mem0
print "Allocation: %0.2f%%" % pd(mem1, mem0)
print "Unreference: %0.2f%%" % pd(mem2, mem1)
print "Collect: %0.2f%%" % pd(mem3, mem2)
print "Overall: %0.2f%%" % pd(mem3, mem0)

Выход:

Allocation: 3034.36%
Unreference: -752.39%
Collect: -2279.74%
Overall: 2.23%

Редактирование:

Я переключился на измерение относительно размер VM процесса для устранения эффектов других процессов в системе.

Среда выполнения C (например, glibc, msvcrt) сжимает кучу, когда смежное свободное пространство наверху достигает постоянного, динамического или настраиваемого порога , С помощью glibc вы можете настроить это с помощью mallopt (M_TRIM_THRESHOLD). Учитывая это, неудивительно, что куча сжимается больше - даже намного больше - чем блок, который вы free.

В 3.x range не создается список, поэтому в приведенном выше тесте не будет создано 10 миллионов int объектов. Даже если это так, тип int в 3.x в основном представляет собой 2.x long, который не реализует freelist.

73
ответ дан eryksun 25 August 2018 в 04:50
поделиться

eryksun ответил на вопрос №1, и я ответил на вопрос № 3 (оригинал № 4), но теперь давайте ответим на вопрос №2:

Почему он выпускает 50.5mb в конкретный - какова сумма, выпущенная на основе?

. На ее основе лежит, в конечном счете, целая серия совпадений внутри Python и malloc, которые очень трудно предсказать.

Во-первых, в зависимости от того, как вы измеряете память, вы можете только измерять страницы, фактически отображаемые в памяти. В этом случае всякий раз, когда страница выгружается пейджером, память будет отображаться как «освобожденная», даже если она не была освобождена.

Или вы можете измерять используемые страницы, которые могут или не могут рассчитывать выделенные, но никогда не затронутые страницы (в системах, которые оптимистически перенастраиваются, например, linux), страницы, которые выделяются, но помечены MADV_FREE и т. д.

Если вы действительно измерение выделенных страниц (на самом деле это не очень полезная вещь, но, похоже, это то, о чем вы спрашиваете), и страницы действительно были освобождены, два обстоятельства, в которых это может произойти: либо вы использовали brk или эквивалент для сокращения сегмента данных (очень редко в настоящее время), или вы использовали munmap или аналогичные для выпуска сопоставленного сегмента. (Существует также теоретически незначительный вариант для последнего, поскольку есть способы освободить часть отображенного сегмента, например, украсть его с помощью MAP_FIXED для сегмента MADV_FREE, который вы сразу же отключите.)

Но большинство программ напрямую не выделяют страницы из памяти; они используют malloc -статический распределитель. Когда вы вызываете free, распределитель может выпустить только страницы в ОС, если вы просто free используете последний живой объект в сопоставлении (или на последних N страницах сегмента данных).

CPython делает это еще более сложным - у него есть настраиваемый 2-уровневый распределитель объектов поверх специализированного распределителя памяти на вверху malloc. (См. исходные комментарии для более подробного объяснения.) И, кроме того, даже на уровне C API, гораздо меньше Python, вы даже не контролируете прямо, когда объекты верхнего уровня deallocated.

Итак, когда вы отпускаете объект, как вы узнаете, собирается ли он выпустить память в ОС? Сначала вы должны знать, что вы выпустили последнюю ссылку (включая любые внутренние ссылки, о которых вы не знали), позволяя GC ее освободить. (В отличие от других реализаций, по крайней мере, CPython освободит объект, как только ему будет разрешено.) Обычно он освобождает по меньшей мере две вещи на следующем уровне вниз (например, для строки вы отпускаете объект PyString и строковый буфер).

Если вы do освободите объект, чтобы узнать, приведет ли это к тому, что следующий уровень не освободит блок хранения объектов, вам необходимо знать внутреннее состояние распределителя объектов, а также как это реализовано. (Это, очевидно, не может произойти, если вы не освободите последнее в блоке, и даже тогда этого может не произойти.)

Если вы сделали , освободите блок чтобы узнать, вызывает ли это вызов free, вы должны знать внутреннее состояние распределителя PyMem, а также то, как оно реализовано. (Опять же, вы должны освободить последний используемый блок в пределах области malloc ed, и даже тогда это может не произойти.)

Если вы сделали free a malloc ed region, чтобы узнать, вызывает ли это munmap или эквивалент (или brk), вы должны знать внутреннее состояние malloc, а также то, как оно реализовано. И этот, в отличие от других, очень специфичен для платформы. (И снова вам, как правило, приходится снимать последнее использование malloc в сегменте mmap, и даже тогда этого может не случиться.)

Итак, если вы хотите понять, почему это случилось, чтобы выпустить ровно 50,5 Мб, вам придется проследить его снизу вверх. Почему malloc удалил страницы размером 50,5 МБ, когда вы сделали эти одни или несколько вызовов free (возможно, чуть больше 50.5 Мб)? Вам нужно будет прочитать вашу платформу malloc, а затем пройти различные таблицы и списки, чтобы увидеть ее текущее состояние. (На некоторых платформах он может даже использовать информацию на системном уровне, что практически невозможно захватить, не делая моментальный снимок системы для проверки в автономном режиме, но, к счастью, обычно это не проблема). И тогда вы должны делайте то же самое на 3 уровнях выше этого.

Итак, единственный полезный ответ на вопрос: «Потому что».

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

И если вы являются делая ограниченную ресурсами разработку, зная, что эти детали бесполезны; вы в значительной степени должны выполнять конечный запуск всех этих уровней и, в частности, mmap необходимую вам память на уровне приложения (возможно, с одним простым, хорошо понятным распределителем зоны приложения, находящимся между ними). ​​

27
ответ дан abarnert 25 August 2018 в 04:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: