Python сколько памяти использует программа

В Python 3.x как мы можем сообщить, сколько памяти использует программа?

Я хотел бы сравнить разные решения одной и той же проблемы с использованием потребляемой памяти, например метрики.

Например, из чего потребляется память:

import itertools def queens (): for p in itertools.permutations (range (8) ): yield [x for x in enumerate (p) ] for q in queens (): err = False for a, b in ( (a, b) for a in q for b in q if a [0] < b [0] ): if abs (a [0] — b [0] ) == abs (a [1] — b [1] ): err = True break if not err: print (q)

А из чего потребляется память:

SIZE=8 A=[0] * SIZE # Array solution s=0 # Global variable to count ‘solutions’, you can delete it! t=0 # Global variable to count recursion ‘tests’, you can delete it! def test(queen, col): global t t+=1 for i in range(1,queen): if(A[queen-i-1]==col): return 0 # Test vertical if(A[queen-i-1]==col-i): return 0 # Test diagonal 1 () if(A[queen-i-1]==col+i): return 0 # Test diagonal 2 (/) return 1 def play(queen): global s for col in range(1,SIZE+1): if(test(queen,col)): # If I can play the queen. A[queen-1]=col # Add queen to the solution Array if(queen==SIZE): # If the last queen was played, this is a solution s+=1 print(«Solution: <>, <>, <>».format(s,t,A)) else: play(queen+1); # If not last queen, play the next one A[queen-1]=0 # Clean the solution Array play(1) # Start putting first queen

Источник: question-it.com

КАК РАБОТАЕТ ПАМЯТЬ В ПИТОНЕ? ССЫЛКИ И ПЕРЕМЕННЫЕ

Профилирование памяти при разработке на Python

В Python встроен механизм, позволяющий автоматически распределять и освобождать память. Тем не менее, понимание принципов работы с памятью может помочь писать более продуманный код.

Немного о сборщике мусора

Важно помнить, что для сборщика мусора наличие ссылок на объект – это сигнал того, что объект удалять нельзя. Выделяемая память на объект освобождается только в случае отсутствия ссылок на объект, удаляя уже не используемый объект.

Для подсчета количества ссылок на объект в Python может использоваться функция sys.getrefcount(). Следует учитывать, что функция создает временную ссылку на объект, увеличивая счетчик ссылок на 1.

import sys my_list = [1, 2, 3] result = my_list print(‘Количество ссылок на объект my_list: ‘, sys.getrefcount(my_list)) # —> ‘Количество ссылок на объект my_list: 3 # Счетчик можно уменьшить вручную, вызвав инструкцию del. del my_list print(my_list)

Однако данный механизм не эффективен для случаев, когда в коде есть циклические ссылки, то есть когда объекты ссылаются друг на друга, не позволяя автоматически освобождать память. При таких условиях счетчик до нуля никогда не уменьшится. Для решения этой проблемы стоит воспользоваться модулем gc, задачей которого является удаление циклических ссылок на объекты.

В Python — нет переменных. И как теперь жить? Python Memory Management на пальцах

Получаем конкретное значение объема потребляемой памяти в коде

Столбец line – номер строки. Столбец mem usage – Использование памяти после выполнения строки. Столбец increment – прирост по памяти текущей строки относительно последней. Столбец line contents – сам профилируемый код.

from timeit import default_timer import memory_profiler def check(fn): «»» Декоратор для замера скорости исполнения кода и потребляемой памяти (с ипользованием memory_profiler) «»» def wrapper(): memory = memory_profiler.memory_usage() start_time = default_timer() result = fn() finish_time = default_timer() memory_2 = memory_profiler.memory_usage() print(f’Память: , скорость: ‘) return result return wrapper

2. Функции sys.getsizeof(), pympler.asizeof()

sys.getsizeof() – возвращает размер объекта, но не включает в себя размер элементов сложного класса, на который ссылается объект. pympler.asizeof() – рекурсивно ищет все вложенные элементы и отображает общий размер файла.

# Numbers (числа)
print(sys.getsizeof(2)) # —> 28
# Tuples (кортежи)
print(sys.getsizeof((2))) # —> 28
# Strings (строки)
print(sys.getsizeof(‘2’)) # —> 50
# Sets (множества)
print(sys.getsizeof(set([2]))) # —> 216
# Lists (списки)
print(sys.getsizeof([2])) # —> 64
# Boolean
print(sys.getsizeof(True)) # —> 28
# Dictionaries (словари)
print(sys.getsizeof()) # —> 232
Читайте также:
Программа чтобы менять фон рабочего стола

Способы уменьшения расхода памяти

  1. Использование генераторов.

2. Конструкция __slots__ при определении классов в ООП.

Использование слотов позволяет сохранить атрибуты в менее затратном по памяти контейнере – списке, кортеже. При этом добавить новые атрибуты невозможно.

import sys from pympler import asizeof class TestClass: __slots__ = [‘a’, ‘b’] def __init__(self, a, b): self.a = a self.b = b object = TestClass(2, 7) print(object.__slots__) # —> [‘a’, ‘b’] print(asizeof.asizeof(object)) # —> 120 print(sys.getsizeof(object)) # —> 56

3. Использование NumPy, Pandas для обработки больших данных.

Использование многомерных массивов может занимать много памяти, поэтому стоит рассмотреть возможности NumPy, поскольку пакет специализирован на экономное потребление памяти при обработке больших данных.

import numpy as np import sys from pympler import asizeof obj = [i for i in range(100000)] print(asizeoff.asizeoff(obj)) # —> 4024456 print(sys.getsizeoff(obj)) # —> 824464 obj_num = np.array([i for i in range(100000)]) print(asizeoff.asizeof(obj_num)) # —> 400112 print(sys.getsizeof(obj_num)) # —> 400096

4. Использовать возможности модуля recordclass.

Модуль похож на namedtuple, кроме одного: он изменяемый. При этом переменные экономнее в потреблении памяти.

import sys from recordclass import recordclass from collections import namedtuple def test(): test_1 = recordclass(‘test_1’, [‘a’, ‘b’, ‘c’, ‘d’]) test_2 = namedtuple(‘test_2’, [‘a’, ‘b’, ‘c’, ‘d’]) test_rc = test_1(a=1, b=7, c=4, d=9) test_nt = test_2(a=1, b=7, c=4, d=9) print(sys.getsizeof(test_rc)) # —> 48 print(sys.getsizeof(test_nt)) # —> 80 test()

5. Использовать возможности специализированных функций, экономящих память, таких как map.

6. Если существует необходимость использовать словари для хранения объектов, то стоит выполнить их сериализацию в json-формат.

import json import sys from pympler import asizeof test_dict = json_dict = json.dumps(test_dict) print(asizeof.asizeof(test_dict)) # —> 14496 print(sys.getsizeof(test_dict)) # —> 4704 print(asizeof.asizeof(json_dict)) # —> 9712 print(sys.getsizeof(json_dict)) # —> 9710

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

Источник: newtechaudit.ru

Python сколько памяти использует программа

Оговоримся, что CPython не взаимодействует напрямую с регистрами и ячейками физической памяти — только с ее виртуальным представлением. В начале выполнения программы операционная система создает новый процесс и выделяет под него ресурсы. Выделенную виртуальную память интерпретатор использует для 1) собственной корректной работы, 2) стека вызываемых функций и их аргументов и 3) хранилища данных, представленного в виде кучи .

В отличие от C/C++, мы не можем управлять состоянием кучи напрямую из Python. Функции низкоуровневой работы с памятью предоставляются Python/C API , но обычно интерпретатор просто обращается к хранилищу данных через диспетчер памяти Python (memory manager).

Диспетчер памяти — своеобразный портье, который регистрирует и расселяет гостей отеля. Каждый постоялец получает ключ с номером комнаты, так что ни один из гостей не может заселиться не в свой номер. Две программы не могут одновременно записать переменную в одно место виртуальной памяти.

Фактически за это отвечает даже не диспетчер задач, который ожидает гостей за регистрационной стойкой, а GIL — глобальная блокировка интерпретатора. GIL гарантирует: в один и тот же момент времени байт-код выполняется только одним потоком. Главное преимущество — безопасная работа с памятью, а основной недостаток в том, что многопоточное выполнение программ Python требует специфических решений.

Очевидно, программа не сама выполняет сохранение и освобождение памяти — ведь мы не пишем соответствующих инструкций. Интерпретатор лишь запрашивает диспетчер памяти сделать это. А диспетчер уже делегирует работу, связанную с хранением данных, аллокаторам — распределителям памяти.

Организация доступной виртуальной памяти

Непосредственно с оперативной памятью взаимодействует распределитель сырой памяти (raw memory allocator). Поверх него работают аллокаторы, реализующие стратегии управления памятью, специфичные для отдельных типов объектов. Объекты разных типов — например, числа и строки — занимают разный объем, к ним применяются разные механизмы хранения и освобождения памяти. Аллокаторы стараются не занимать лишнюю память до тех пор, пока она не станет совершенно необходимой — этот момент определен стратегией распределения памяти CPython.

Python использует динамическую стратегию, то есть распределение памяти выполняется во время выполнения программы. Виртуальная память Python представляет иерархическую структуру, оптимизированную под объекты Python размером менее 256 Кб:

Читайте также:
Программа кружка исследовательская деятельность

Схематическое представление структуры виртуально памяти Python: арены состоят из пулов, пулы составлены из блоков

  • Арена — фрагмент памяти, расположенный в пределах непрерывного блока оперативной памяти объемом 256 Кб. Объекты размером более 256 Кб направляются в стандартный аллокатор C.
  • Пул — блок памяти внутри арены, занимающий 4 Кб, что соответствует одной странице виртуальной памяти. То есть одна арена включает до 256/4 = 64 пулов.
  • Блок — элемент пула размером от 16 до 512 байт. В пределах пула все блоки имеют одинаковый размер. Размер блока определяется тем, сколько байт требуется для представления конкретного объекта. Размеры блоков кратны 16 байт. То есть существует всего 512/16 = 32 классов ( size class ) блоков. То есть в одном пуле, в зависимости от класса, может находиться от 8 до 256 блоков.

Блок

Блок содержит не более одного объекта Python и находится в одном из трех состояний:

  1. untouched — блок еще не использовался для хранения данных;
  2. free — блок использовался механизмом памяти, но больше не содержит используемых программой данных;
  3. allocated — блок хранит данные, необходимые для выполнения программы.

В пределах пула блоки free организованы в односвязный список с указателем freeblock . Если аллокатору для выделения памяти не хватит блоков списка freeblock , он задействует блоки untouched . Освобождение памяти означает всего лишь то, что аллокатор меняет статус блока с allocated на free и начинает отслеживать блок в списке freeblock .

Пул

Пул может находиться в одном из трех состояний: used (занят), full (заполнен), empty (пуст). Пустые пулы отличаются от занятых отсутствием блоков allocated и тем, что для них пока не определен size class . Пулы full полностью заполнены блоками allocated и недоступны для записи. Стоит освободиться любому из блоков заполненного пула — и он помечается как used .

Пулы одного типа и одного размера блоков организованы в двусвязные списки. Это позволяет алгоритму легко находить доступное пространство для блока заданного размера. Алгоритм проверяет список usedpools и размещает блок в доступном пуле. Если в usedpools нет ни одного подходящего пула для запроса, алгоритм использует пул из списка freepools , который отслеживает пулы в состоянии empty .

Арена

Арены содержат пулы любых видов и организованы в двусвязный список usable_arenas . Список отсортирован по количеству доступных пустых пулов. Чем меньше в арене таких пулов, тем она ближе к началу списка. Для размещения новых данных выбирается область, наиболее заполненная данными.

Информацию о текущем распределении памяти в аренах, пулах и блоках можно посмотреть, запустив функцию sys._debugmallocstats() :

>>> import sys >>> sys._debugmallocstats() Small block threshold = 512, in 32 size classes. class size num pools blocks in use avail blocks —— —- ——— ————- ———— 0 16 1 212 41 1 32 6 629 127 2 48 28 2317 35 3 64 118 7386 48 4 80 104 5164 36 5 96 17 696 18 6 112 11 372 24 7 128 7 212 5 8 144 37 1014 22 9 160 7 174 1 10 176 64 1426 46 11 192 4 66 18 12 208 3 42 15 13 224 11 181 17 14 240 5 65 15 15 256 3 35 10 16 272 2 23 5 17 288 3 28 14 18 304 15 184 11 19 320 2 17 7 20 336 2 14 10 21 352 2 13 9 22 368 2 15 7 23 384 1 9 1 24 400 3 23 7 25 416 4 31 5 26 432 6 42 12 27 448 4 28 8 28 464 4 26 6 29 480 4 27 5 30 496 5 33 7 31 512 6 37 5 # arenas allocated total = 10 # arenas reclaimed = 2 # arenas highwater mark = 8 # arenas allocated current = 8 8 arenas * 262144 bytes/arena = 2,097,152

Чтобы не произошло утечки памяти, диспетчер памяти должен отследить, что вся выделенная память освободится после завершения работы программы. То есть при завершении программы CPython дает задание очистить все арены.

Именно количество используемых арен определяет объем оперативной памяти, занимаемой программой на Python — если в арене все пулы в состоянии empty , СPython делает запрос на освобождение этого участка виртуальной памяти. Но уже понятно: чтобы пулы стали empty , все их блоки должны быть free или untouched . Получается, нужно понять, как CPython освобождает память.

Читайте также:
Программа чтобы делать календари

Освобождение памяти: счетчик ссылок, сборщик мусора

Для освобождения памяти используются два механизма: счетчик ссылок и сборщик мусора.

Всё в Python является объектами, а прародителем всех типов объектов в реализации CPython является PyObject . От него наследуются все остальные типы. В PyObject определены счетчик ссылок и указатель на фактический тип объекта. Счетчик ссылок увеличивается на единицу, когда мы создаем что-то, что обращается к объекту, например, сохраняем объект в новой переменной. И наоборот, счетчик уменьшается на единицу, когда мы перестаем ссылаться на объект.

Счетчик ссылок любого объекта можно проверить с помощью sys.getrefcount() . Учтите, что передача объекта в getrefcount() увеличивает счетчик ссылок на 1, так как сам вызов метода создает еще одну ссылку. Когда счетчик уменьшается до нуля, происходит вызов аллокатора для освобождения соответствующих блоков памяти.

>>> import sys >>> a = <> >>> b = a >>> sys.getrefcount(a) 3 >>> del b >>> sys.getrefcount(a) 2

Однако счетчик ссылок неспособен отследить ситуации с циклическими ссылками. К примеру, возможна ситуация, когда два объекта ссылаются друг на друга, но оба уже не используются программой. Для борьбы с такими зависимостями используется сборщик мусора ( garbage collector ).

Если счетчик ссылок является свойством объекта, то сборщик мусора — механизм, который запускается на основе эвристик. Задача этих эвристик — снизить частоту и объем очищаемых данных. Основная стратегия заключается в разделении объектов на поколения: чем больше сборок мусора пережил объект, тем он значимее для выполнения работы программы. Сборщик мусора имеет интерфейс в виде модуля gc .

Заключение

Сохранение и освобождение блоков памяти требует времени и вычислительных ресурсов. Чем меньше блоков задействовано, тем выше скорость работы программы. Позволим себе дать несколько советов, касающихся экономной работы с памятью:

  1. Обращайте внимание на работу с неизменяемыми объектами . К примеру, вместо использования оператора + для соединения строк используйте методы .join() , .format() или f-строки.
  2. Избегайте вложенных циклов. Создание сложных вложенных циклов приводит к генерации чрезмерно большого количества объектов, занимающих значительную часть виртуальной памяти. Большинство задач, решаемых с помощью вложенных циклов, разрешимы методами модуля itertools.
  3. Используйте кэширование . Если вы знаете, что функция или класс используют или генерируют набор однотипных объектов, применяйте кэширование . Часто для этого достаточно добавить всего лишь один декоратор из библиотеки functools .
  4. Профилируйте код. Если программа начинает «тормозить», то профилирование — самый быстрый способ найти корень всех зол.

На ранних этапах работы с кодом Python можно вполне обойтись стандартными средствами Python. Но по мере разрастания кодовой базы и приближения к коммерческому использованию кода производительность становится одним из ключевых факторов. Многие задачи, связанные с производительностью Python, лежат в области понимания устройства инструмента и конкретной реализации языка. Не пожалейте времени на изучение исходного кода CPython, находящегося в свободном доступе в репозитории на GitHub .

На Python создают прикладные приложения, пишут тесты и бэкенд веб-приложений, автоматизируют задачи в системном администрировании, его используют в нейронных сетях и анализе больших данных. Язык можно изучить самостоятельно, но на это придется потратить немало времени.

Если вы хотите быстро понять основы программирования на Python, обратите внимание на онлайн-курс «Библиотеки программиста». За 30 уроков (15 теоретических и 15 практических занятий) под руководством практикующих экспертов вы не только изучите основы синтаксиса, но и освоите две интегрированные среды разработки (PyCharm и Jupyter Notebook), работу со словарями, парсинг веб-страниц, создание ботов для Telegram и Instagram, тестирование кода и даже анализ данных. Чтобы процесс обучения стал более интересным и комфортным, студенты получат от нас обратную связь. Кураторы и преподаватели курса ответят на все вопросы по теме лекций и практических занятий.

Источники

  • https://docs.python.org/3/c-api/index.html
  • https://realpython.com/python-memory-management/

Источник: proglib.io

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru