Рубрики
Без рубрики

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

Автор оригинала: Guest Contributor.

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

Вступление

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

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

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

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

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

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

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

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

Например:

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

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

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

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

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

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

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

import gc
print(gc.get_threshold())

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

(700, 10, 10)

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

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

gc.set_threshold(900, 15, 15)

В приведенном выше примере мы увеличили пороговое значение для всех 3 поколений. Увеличение порогового значения приведет к снижению частоты запуска сборщика мусора. Обычно нам не нужно слишком много думать о сборке мусора 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 . Первый элемент объекта списка относится к самому себе. Количество ссылок на объект списка всегда больше нуля, даже если он удален или находится вне области действия программы. Следовательно, объект list не является мусором, собранным из-за циклической ссылки. Механизм сборщика мусора в Python будет автоматически проверять и периодически собирать циклические ссылки.

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

Вывод

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