Основы управления памятью в Python

Введение Управление памятью - это процесс эффективного выделения, освобождения и координации памяти, чтобы все различные процессы выполнялись плавно и могли оптимально обращаться к различным системным ресурсам. Управление памятью также включает очистку памяти от объектов, к которым больше нет доступа. В Python диспетчер памяти отвечает за такие задачи, периодически выполняясь для очистки, выделения и управления памятью. В отличие от C, Java и других языков программирования Py

Вступление

Управление памятью - это процесс эффективного выделения, освобождения и координации памяти, чтобы все различные процессы выполнялись плавно и могли оптимально обращаться к различным системным ресурсам. Управление памятью также включает очистку памяти от объектов, к которым больше нет доступа.

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

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

Сборка мусора Python

Как объяснялось ранее, Python удаляет объекты, на которые больше нет ссылок в программе, чтобы освободить место в памяти. Этот процесс, в котором Python освобождает блоки памяти, которые больше не используются, называется сборкой мусора. Сборщик мусора Python (GC) запускается во время выполнения программы и запускается, если счетчик ссылок уменьшается до нуля. Счетчик ссылок увеличивается, если объекту присваивается новое имя или он помещается в контейнер, например кортеж или словарь. Точно так же счетчик ссылок уменьшается, когда ссылка на объект переназначается, когда ссылка на объект выходит за пределы области видимости или когда объект удаляется.

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

Объекты Python в памяти

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

Например:

 >>> x = 5 
 >>> print(x) 
 5 
 >>> del x 
 >>> print(x) 
 Traceback (most reent call last): 
 File "<mem_manage>", line 1, in <module> 
 print(x) 
 NameError : name 'x' is not defined 

Если вы посмотрите на первые 2 строки приведенной выше программы, объект x известен. Когда мы удаляем объект x и пытаемся его использовать, мы получаем сообщение об ошибке о том, что переменная x не определена.

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

Изменение сборщика мусора

У сборщика мусора Python есть три поколения, в которых классифицируются объекты. Новый объект в начальной точке своего жизненного цикла - это сборщик мусора первого поколения. Поскольку объект остается после сборки мусора, он будет передан следующим поколениям. У каждого из 3 поколений сборщика мусора есть порог. В частности, когда превышен порог количества выделений минус количество de0allocations, это поколение запустит сборку мусора.

Более ранние поколения также собирают мусор чаще, чем старшие поколения. Это связано с тем, что более новые объекты будут выброшены с большей вероятностью, чем старые.

Модуль gc включает в себя функции для изменения порогового значения, запуска процесса сборки мусора вручную, отключения процесса сборки мусора и т. Д. Мы можем проверить пороговые значения разных поколений сборщика мусора с помощью get_threshold() :

 import gc 
 print(gc.get_threshold()) 

Пример вывода:

 (700, 10, 10) 

Как видите, здесь у нас есть порог в 700 для первого поколения и по 10 для каждого из двух других поколений.

Мы можем изменить пороговое значение для запуска процесса сборки мусора, используя метод set_threshold() модуля gc

 gc.set_threshold(900, 15, 15) 

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

Зачем выполнять сборку мусора вручную?

Мы знаем, что интерпретатор Python отслеживает ссылки на объекты, используемые в программе. В более ранних версиях Python (до версии 1.6) интерпретатор Python использовал только механизм подсчета ссылок для обработки памяти. Когда счетчик ссылок падает до нуля, интерпретатор Python автоматически освобождает память. Этот классический механизм подсчета ссылок очень эффективен, за исключением того, что он не работает, когда программа имеет циклы ссылок . Цикл ссылок происходит, если один или несколько объектов ссылаются друг на друга, и, следовательно, счетчик ссылок никогда не достигает нуля.

Рассмотрим пример.

 >>> def create_cycle(): 
 ... list = [8, 9, 10] 
 ... list.append(list) 
 ... return list 
 ... 
 >>> create_cycle() 
 [8, 9, 10, [...]] 

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

Для этого мы можем использовать gc.collect() модуля gc

 import gc 
 n = gc.collect() 
 print("Number of unreachable objects collected by GC:", n) 

gc.collect() возвращает количество собранных и освобожденных объектов.

Есть два способа выполнить сборку мусора вручную: сборку мусора по времени или по событиям.

Сборка мусора на основе времени довольно проста: gc.collect() вызывается через фиксированный интервал времени.

Сборка мусора на основе событий вызывает gc.collect() после того, как событие происходит (т. Е. Когда приложение закрывается или приложение остается бездействующим в течение определенного периода времени).

Давайте разберемся с ручной сборкой мусора, создав несколько эталонных циклов.

 import sys, gc 
 
 def create_cycle(): 
 list = [8, 9, 10] 
 list.append(list) 
 
 def main(): 
 print("Creating garbage...") 
 for i in range(8): 
 create_cycle() 
 
 print("Collecting...") 
 n = gc.collect() 
 print("Number of unreachable objects collected by GC:", n) 
 print("Uncollectable garbage:", gc.garbage) 
 
 if __name__ == "__main__": 
 main() 
 sys.exit() 

Результат выглядит следующим образом:

 Creating garbage... 
 Collecting... 
 Number of unreachable objects collected by GC: 8 
 Uncollectable garbage: [] 

Приведенный выше сценарий создает объект списка, на который ссылается переменная с творческим названием list . Первый элемент объекта списка ссылается на себя. Счетчик ссылок объекта списка всегда больше нуля, даже если он удален или выходит за рамки программы. Следовательно, list не собирается сборщиком мусора из-за циклической ссылки. Механизм сборщика мусора в Python будет автоматически периодически проверять и собирать циклические ссылки.

В приведенном выше коде, поскольку счетчик ссылок равен как минимум 1 и никогда не может достигнуть 0, мы принудительно собрали объекты мусором, вызвав gc.collect() . Однако помните, что не следует часто принудительно выполнять сборку мусора. Причина в том, что даже после освобождения памяти сборщику мусора требуется время, чтобы оценить соответствие объекта сборщику мусора, отнимая процессорное время и ресурсы. Кроме того, не забудьте вручную управлять сборщиком мусора только после полного запуска приложения.

Заключение

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

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus