- Работа памяти в Python
- Организация доступной виртуальной памяти
- Блок
- Пул
- Арена
- Освобождение памяти: счётчик ссылок и сборщик мусора
- Советы
- Заключение
- Управление памятью в Python
- Понимание управления памятью в Python
- Вывоз мусора
- Отсчет ссылки
- Выделение памяти
- 1. Распределение памяти стека
- 2. Распределение кучи памяти
- Заключение
- Рекомендации
- Читайте ещё по теме:
Работа памяти в Python
Python — интерпретируемый язык программирования, поэтому перед выполнением код транслируется в машиночитаемые инструкции — байт-код. Байт-код интерпретируется виртуальной машиной, определяемой реализацией языка, например, стандартной — CPython.
Python не взаимодействует с памятью — только с её виртуальным представлением. В процессе выполнения программы операционная система создаёт процесс и выделяет под него ресурсы. В отличие от С/С++ мы не можем управлять памятью из кучи напрямую, а делаем это посредством memory manager, который и обращается к памяти через Python/C API.
Организация доступной виртуальной памяти
Непосредственно с сырой памятью взаимодействует raw memory allocator. Поверх него работают аллокаторы, специфичные для отдельных типов объектов.
Python использует динамическую стратегию распределения памяти, то есть распределение памяти происходит во время выполнения программы.
Виртуальная память представляет собой иерархическую структуру, оптимизированную под блоки размером 256Кб.
Блок
Содержит не более одного объекта и находится в одном из трёх состояний:
- untouched — блок ещё не использовался
- free — блок использовался механизмом памяти, но больше не содержит использованных программой данных
- allocated — блок хранит данные
Пул
Пул также имеет три состояния:
- used — занят
- full — заполнен
- empty — пуст (от used отличаются отсутствием allocated блоков) Пулы одного типа и одного размера блоков организованы в двусвязные списки.
Арена
Хранит в себе пулы любых видов. Арены хранятся в двусвязном списке и отсортированы по количеству доступных пустых пулов.
Освобождение памяти: счётчик ссылок и сборщик мусора
Так в Python всё является объектом, то каждое существо имеет прародителя — это PyObject. В нём определены счётчики ссылок и указатель на фактический тип объекта. Это хорошо работает пока Python не сталкивается с циклическим созданием ссылок. Например, когда два объекта ссылаются друг на друга. Для борьбы с такими проблемами поднимается сборщик мусора.
Советы
- Обращайте внимание на работу с неизменяемыми объектами. К примеру, вместо присваивания строк, используйте .join() или .format() .
- Избегайте вложенных циклов. Это приводит к созданию чрезмерно большого количество объектов в виртуальной памяти процесса.
- Используйте кэширование.
- Профилируйте код.
Заключение
При использовании базовых возможностей Python знание о внутреннем устройстве память в интерпретаторе не обязательно, но когда дело доходит до широкомасштабных коммерческих проектов, то узнать тонкости для лучшей оптимизации кодовой базы всё же будет полезным.
Управление памятью в Python
Управление памятью – это процесс хранения памяти динамически и освобождает его, когда он не используется.
Управление памятью – это процесс хранения памяти динамически и освобождает его, когда он не используется.
Понимание управления памятью в Python
В Python это распределение и освобождение памяти выполняются автоматически коллектором мусора Python, созданным разработчиками Python, чтобы пользователи не должны заниматься ручной сборной мусором.
Вывоз мусора
Коллекция мусора в Python – это процесс управления памятью для освобождения неиспользованной и нежелательной памяти для наших программ переводчика. В Python это делается автоматически.
Сборщик мусора находит объект, который не имеет ссылки на его, а затем удаляет этот объект из памяти кучи. Для этого Python использует алгоритм отсчета ссылок.
class Python: def __init__(self): print('The object is created.') def __del__(self): print('The object is destroyed.') obj1 = Python() obj2 = obj1 obj3 = obj1 print("Set obj1 to None") obj1 = None print("Set obj2 to None") obj2 = None print("Set obj3 to None") obj3 = None
The object is created. Set obj1 to None Set obj2 to None Set obj3 to None The object is destroyed.
Здесь мы создали объект класса Python и передал свою ссылку на obj1, obj2, obj3 Отказ Это делает ссылку на счет этого объекта 3. Тогда, когда мы присваиваем эти ссылки на Нет Все ссылки из этого объекта удаляются и становятся 0. Поскольку нет никаких ссылок на объект, он разрушен сборщиком мусора Python, а метод __del __ () выполнен.
Отсчет ссылки
Подсчет ссылки в Python – это методика, в которой объект определяется из памяти, когда нет никаких ссылок, указывающих на него. Когда ссылочный счетчик становится ноль, объект удаляется.
У нас есть встроенная функция getrefcount () Присутствует в модуле Python sys который возвращает количество ссылок на данный объект Python.
import sys str = "Welcome to Python" print(sys.getrefcount(str)) arr = [] arr.append(str) # appending to an array print(sys.getrefcount(str)) dict = <> dict['str'] = str # adding to a dictionary print(sys.getrefcount(str)) arr = [] # resetting the array sys.getrefcount(str) dict['my_str'] = "Some other string" print(sys.getrefcount(str))
Значение ссылочного подсчета – это один высокий, чем то, что вы ожидаете, потому что он также считает, что объект, переданный в функции sys.getrefcount ().
Иногда ссылочный счетчик объекта никогда не достигает нуля. Это происходит потому, что объект относится к себе. Это называется Опорный цикл Отказ
import sys x = [] x.append(x) # x contains reference to itself print("Reference count of object is",sys.getrefcount(x))
Reference count of object is 3
Здесь создается объект X, который относится к себе. Ссылочный счет никогда не достигнет 0, так как у него есть собственная ссылка. Объект X будет занимать память, пока не вызывается сборщик мусора Python.
Когда объект объявлен во всем мире, ссылочный счетчик объекта никогда не может стать нулевым.
Выделение памяти
Чтобы понять распределение памяти, мы должны понимать память произвольного доступа (RAM). ОЗУ также называется основной памятью, которая позволяет хранить информацию и получить на компьютере.
В верхней части оперативной памяти у нас есть стек и внизу, у нас есть куча. Куча отвечает за хранение переменных/значений, а стек несет ответственность за проведение ссылок на объект в куче.
В Python, когда более одной переменных имеют одинаковое значение, вторая переменная, указывающая на исходное значение, создается в куче.
x = 5 y = x if(id(x) == id(y)): print("x and y refer to the same object") x = x+1 if(id(x) != id(y)): print("x and y refer to different objects") z = 5 if(id(y) == id(y)): print("y and z refer to same memory")
x and y refer to the same object x and y refer to different objects y and z refer to same memory
Есть два типа ассигнований памяти:
1. Распределение памяти стека
Распределение памяти стека – это хранение статической памяти внутри определенной функции или вызова метода. Когда функция называется, память хранится в стеке вызовов функций. Любые локальные инициализации переменных хранятся в стеке вызовов и удалены после возврата функции.
Итак, когда мы запуская нашу программу, все функции впервые хранятся в стеке вызовов, а затем удалены, когда функция возвращается.
def func(): #These initializations are stored in stack memory x = 10 y = "Apple"
2. Распределение кучи памяти
Распределение кучи памяти – это хранение памяти, которое необходимо вне конкретной функции или вызова метода. Эта память используется в программе в глобальном объеме.
Память кучи не связана с структурой данных кучи. Это просто большое пространство памяти, предоставляемое пользователям, когда они хотят выделить и освобождать переменные/значения.
В Python Geap Memory управляет самим интерпретатором, и пользователь не имеет контроля над ним.
def func() #Allocates memory for 5 integers in heap memory x=[None]*5
Заключение
Программисты влюбились в Python для его превосходных возможностей управления памятью. По сравнению со многими другими языками программирования низкого уровня Python сделал его ветером для работы с переменными, не беспокоясь о чрезмерных ресурсах.