Python количество ссылок на объект

Создание и удаление объектов. Сборщик мусора#

Итого, в python все данные представляются в виде объектов, доступ к которым осуществляется или через имена/ссылки/идентификаторы в исходном коде программы. Разберемся, как эти объекты создаются и удаляются.

Создание объектов#

Создаются объекты в результате вычисления выражений python . Рассмотрим следующую строку кода.

Когда интерпретатор исполняет исходный код, он сначала вычисляет выражение справа от оператора “ = ”.

Так как это составное выражение, то, чтобы его вычислить, необходимо сначала вычислить результаты составляющих его подвыражений 1001 и int(«1002») .

  1. Первое из них ( 1001 ) является литералом целого числа 1001. Его интерпретация приводит к созданию целочисленного объекта со значением 1001.
  2. Второе выражение ( int(«1002») ) тоже является составным.
    1. Сначала вычисляется выражение «1002» , указанное в качестве аргумента функции int . Это выражение является литералом строки, а значит его интерпретация приводит к созданию строкового объекта со значением «1002» .
    2. Далее этот объект передаётся на вход функции int , что приводит к созданию целочисленного объекта со значением 1002 .

    Затем интерпретатор применяет операцию сложения к объектам целочисленного типа, что приводит к созданию ещё одного целочисленного объекта со значением 2003.

    Далее имя x связывается с этим объектом. Итого, в результате вычисления этой строки кода была создано 4 объекта.

    ../../_images/expressions.png

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

    Механизм подсчета ссылок на объект#

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

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

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

    Так как python проводит ряд оптимизация при работе с неизменяемыми объектами (таких, как интернирование строк и малых целых чисел), то для чистоты эксперимента создадим изменяемый объект — пустой список, свяжем его с именем a и выведем количество ссылок на него.

    from sys import getrefcount a = [] print(getrefcount(a)) 

    Видим, что количество ссылок на этот объект равняется двум: одна из этих ссылок — имя a , другая — временная ссылка, созданная внутри функции getrefcount при передаче этого объекта в качестве аргумента.

    ../../_images/refcount_1.png

    Создадим ещё пару ссылок на этот объект и снова напечатаем количество ссылок на список.

    b = a print(getrefcount(a)) c = a print(getrefcount(a)) 

    Видим, что счетчик вырастает на 1, каждый раз, когда мы связываем новое имя с исходным объектом.

    ../../_images/refcount_2.png

    Кроме имен программы на объект могут ссылаться другие объект (или даже тот же самый в предельном случае). Например, список хранит в себе ссылки на свои элементы.

    L = [a, a, a] print(getrefcount(a)) 

    Созданный список L=[a, a, a] содержит 3 ссылки на исходный список, что отражается на увеличении счетчика ссылок.

    ../../_images/refcount_3.png

    Также временные ссылки создаются при передаче объекта в качестве аргумента функции. Именно этим и объясняется увеличенное значение, возвращаемое функцией getrefcount .

    Удаление объектов в python . Ключевое слово del #

    Механизм подсчета ссылок используется для определения того, какие объекты можно удалять. Действительно, если ссылок на объект нет, то значит он недостижим для программы и его можно смело удалять.

    Чтобы счетчик ссылок обнулился, необходимо чтобы пропали все ссылки на этот объект. Такое может происходить по разным причинам. Например, если связать какое-то существующее в программе имя с новым объектом, то пропадёт одна ссылка на объект, на которое это имя ссылалось прежде.

    Видим, что связывание имени b с целочисленным объектом 0 привело к тому, что количество ссылок на пустой список, на который ссылалось имя b прежде, упало на 1.

    ../../_images/refcount_4.png

    Кроме того с помощью ключевого слова del можно просто удалить имя из программы, а вместе с этим и ссылку на объект, на которое это имя ссылается. Чтобы удалить имя name из текущего пространства имён, используется следующий синтаксис.

    Удалим имя c и убедимся, что количество ссылок упадёт ещё на 1.

    ../../_images/refcount_5.png

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

    Если удаляется объект, то удаляются все его ссылки на другие объект. Чтобы продемонстрировать этот эффект, удалим список L и убедимся, что количество ссылок на a упадёт на 3.

    ../../_images/refcount_6.png

    Сборщик мусора#

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

    Воспроизведем такую ситуацию на примере двух списков.

    L1 = [] L2 = [] L1.append(L2) L2.append(L1) print(L1, L2) 

    Схема ниже иллюстрирует сложившуюся ситуацию.

    ../../_images/cycle.png

    Удалим изначальные ссылки L1 и L2 .

    Теперь пропали все внешние ссылки на циклическую группу этих списков, т.е. они недостижимы для программы, но сами списки все ещё ссылаются друг на друга.

    ../../_images/unreachable_cycle.png

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

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

    Модуль gc предоставляет интерфейс к взаимодействию со сборщиком мусора. В частности, можно отключить автоматическую сборку мусора методом disable, например, если сценарий программы не подразумевает создание циклических структур, или если стабильная производительность программы важнее потенциальной утечки памяти. Кроме отключения сборщика мусора, с помощью этого модуля можно в ручную его запускать методом collect.

    Подробно прочитать о том, как работает сборщик мусора в python можно по ссылке в документации.

    Изменяемые и неизменяемый типы объектов

    Источник

    Подсчет ссылок и сборка мусора в Python

    26 ноября 2015 г. Archy Просмотров: 17055 RSS Обсудить
    Python для начинающих

    Подсчет ссылок и сборка мусора в Python

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

    a = 37 # Создается объект со значением 37 b = a # Увеличивается счетчик ссылок на объект 37 c = [] c.append(b) # Увеличивается счетчик ссылок на объект 37

    В этом примере создается единственный объект, содержащий значение 37. Переменная a, это всего лишь имя, ссылающееся переменной b, вслед чего b становится еще одним именем того же самого объекта, при этом счетчик ссылок на объект увеличивается на 1. Точно так же, когда переменная b помещается в список, счетчик ссылок увеличивается на единицу.

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

    Счетчик ссылок уменьшается, когда вызывается инструкция del или когда поток выполнения покидает область видимости ссылки(или при присваивании другого значения). Например:

    del a # Уменьшает счетчик ссылок на объект 37 b = 42 # Уменьшает счетчик ссылок на объект 37 с[0] = 2.0 # Уменьшает счетчик ссылок на объект 37

    Определить текущее количество ссылок на объект можно с помощью функции sys.getrefcount(). Например, создаем переменную Иван Франко которая будет ссылаться на строку «критика на творчество Франко».

    >>> a = 37 >>> import sys >>> IvanFranko = "критика на творчество Франко" >>> length = len(IvanFranko) # длина строки >>> sys.getrefcount(IvanFranko) 2 >>> sys.getrefcount(length) 9 >>> length 28 

    Собственно, на Ubuntu все выглядит следующим образом:

    Подсчет ссылок и сборка мусора в Python

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

    На сайте https://doctorsmm.com/ можно купить очень недорогие комментарии в Инстаграм к любому посту или нескольким публикациям сразу. При этом Вы вправе выбрать формат сообщений: рандомные, смайлы, живые или микс.

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

    a = <> b = <> a['b'] = b # a содержит ссылку на b b['a'] = a # b содержит ссылку на a del a del b 

    В этом примере инструкция del уменьшает счетчики ссылок на объекты a и b и уничтожает имена, ссылавшиеся на объекты в памяти. Однако поскольку объекты содержат ссылки друг на друга, счетчики ссылок не достигают нуля и объекты продолжают существовать(что приводит к утечке памяти).

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

    Источник

    Читайте также:  Getfile telegram bot api java
Оцените статью