Letysite.ru

IT Новости с интернет пространства
1 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Сборщик мусора gc в рнр

Блог о починке примусов

вторник, 17 декабря 2019 г.

Сборка мусора в php

Недавно встретился хороший пост для начинающих о сборке мусора (он же garbage collection ) в php. Далее я попытаюсь перевести этот пост на русский и добавить немного собственных данных. Ссылка на оригинальный пост — в конце.

Начнем с того, что так как php — язык интерпретируемый, то вам не нужно заморачиваться управлением памятью — выделением памяти, и что более важно — очисткой памяти. Этим в php занимается специальный механизм, называемый сборкой мусора (или garbage collection, или же gc).

Сборка мусора работает тремя способами:

  1. При уходе переменной из области видимости
  2. При подсчете ссылок
  3. При сборе циклических ссылок

Как только переменная уходит из области видимости и больше нигде не используется — она автоматически собирается gc. Также с помощью unset можно явно определить, что переменную пора собирать gc . Пример кода:

function display_var() <
$foo = «bar»;
echo $foo;
>

$user = «Mister X»;
unset($user);

В данном коде:

  • переменная $foo будет автоматически собрана gc сразу после завершения выполнения функции display_var
  • переменная $user будет собрана gc, так как она явно удалена с помощью unset

С подсчетом ссылок разобраться чуть сложнее. Официальная часть здесь.

Кратко — для того чтобы понять, можно ли безопасно собрать переменную с помощью garbage collection, используется механизм подсчета ссылок. Данный механизм заключается в следующем — при создании переменной в php создается не просто переменная, а контейнер типа zval , в котором помимо собственно типа и значения переменной, хранится еще два поля — ref_count и is_ref . Далее, если вы присваиваете другой переменной значение этой переменной, то контейнер не копируется с имеющимися данными, а php просто увеличивает ref_count на единицу, так как контейнер используется уже двумя переменными. И так далее.

Как только в какой-то момент переменная удаляется (с помощью unset или ухода из зоны видимости), счетчик ref_count в контейнере уменьшается. Как только счетчик дошел до нуля — считается, что контейнер готов к сборке мусора.

Мониторить состояние контейнера можно при наличии расширения Xdebug с помощью функции xdebug_debug_zval .

Сборка мусора при наличии циклических ссылок не так сложна, как предыдущий пункт. В этом случае сборка мусора активируется в тот момент, когда в памяти находится 10000 объектов с циклическими ссылками, и один из них уходит из области видимости. Значение 10000 установлено на уровне ядра php и может быть изменено только путем изменения исходного кода и его перекомпиляции. Однако, процесс сборки мусора можно запустить явно, не дожидаясь накопления 10000 объектов, с помощью метода gc_collect_cycles .

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

  • вызвать метод gc_disable
  • установить значение zend.enable_gc в false в файле php.ini ( gc_disable делает то же самое)

Также можно отметить, что изменения в php7.3 серьезно улучшили механизм сборки мусора — в оригинальном посте можно увидеть бенчмарки сравнения предыдущих релизов и версии 7.3, плюс появилась полезная функция gc_status, выводящая данные об использовании gc. А при наличии уже упомянутого Xdebug можно получить еще больше информации с помощью функции xdebug_start_gcstats .

Вот все основные моменты, что следует знать и помнить о сборке мусора. Оригинальная статья с некоторыми дополнительными плюшками — тут.

php сборка мусора во время работы скрипта

У меня есть php-скрипт, который работает на cron, который может занять до 15 минут для выполнения. Через регулярные промежутки времени он выплевывает memory_get_usage (), чтобы я мог видеть, что происходит. В первый раз он говорит мне, что я использую 10 мегабайт. Когда сценарий заканчивается, я нахожусь в 114 мегабайт!

делает ли PHP сборку мусора во время работы скрипта? Или что происходит со всеми этими воспоминаниями? Есть ли что-то, что я могу сделать, чтобы заставить сбор мусора. Задача, которой является мой скрипт выполнение-это ночной импорт пары тысяч узлов в Drupal. Поэтому он делает то же самое много раз.

4 ответов

ключ в том, что вы unset ваши глобальные переменные, как только они вам не нужны.

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

в PHP хранит счетчик ссылок для всех переменных и уничтожает их (в большинстве случаев), как только этот счетчик становится равным нулю. Объекты имеют один внутренний счетчик ссылок и переменные сами (ссылки на объекты) имеют по одному счету ссылок. Когда все ссылки на объект были уничтожены, потому что их ссылочные coutns попали в 0, сам объект будет уничтожен. Пример:

но рассмотрим следующий сценарий:

эти циклические ссылки-это то, где запускается сборщик мусора PHP 5.3. Вы можете явно вызвать сборщик мусора с gc_collect_cycles .

PHP вывоз мусора в большинстве счетчик ссылки (он имеет некоторое обнаружение цикла.) Если вы сохраняете ссылки, которые все еще доступны вокруг них, они легко сложатся, если не будут освобождены.

использовать unset () чтобы освободить переменные, которые вы больше не используете. Если вы просто перезаписываете переменные (например, с null), это позволит только GC уменьшить объем пространства, требуемого этой переменной, но не столько, сколько unset, который фактически позволяет уничтожение ссылочного значения.

вы также должны правильно освободить ресурсы, и т. д. которые вы используете.

вы увидите, что увеличить объем памяти во время выполнения в ГК является бесплатным, чтобы освободить его по собственному усмотрению, например, когда есть свободные циклы процессора или когда он начинает нехватке памяти.

использовать unset() как можно чаще проверяйте используемую память. да, php выполняет сборку мусора во время выполнения при нескольких условиях. вот полезный в должности on php.net.

Если память увеличивается настолько, то вы, вероятно, не освобождаете ее. Вы создали утечку памяти. Сбор мусора не поможет вам, если вы не отменяете переменные, уничтожаете объекты и / или они выходят за рамки.

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

Информационный портал по безопасности

Ломаем сбор мусора и десериализацию в PHP

Эй, PHP, эти переменные выглядят как мусор, согласен?
Нет? Ну, посмотри-ка снова…

tl;dr:
Мы обнаружили две use-after-free уязвимости в алгоритме сбора мусора в PHP:

  • Одна присутствует во всех версиях PHP 5 >= 5.3 (исправлена в PHP 5.6.23).
  • Вторая — во всех версиях PHP >= 5.3, включая версии PHP 7 (исправлена в PHP 5.6.23 и PHP 7.0.8).
Читать еще:  Помогите установить флеш плеер

Уязвимости могут удалённо применяться через PHP-функцию десериализации. Используя их, мы отыскали RCE на pornhub.com, за что получили премию в 20 000 долларов плюс по 1000 долларов за каждую из двух уязвимостей от комитета Internet Bug Bounty на Hackerone.

Занимаясь проверкой Pornhub, мы обнаружили две критические утечки в алгоритме СМ (How we broke PHP, hacked Pornhub and earned $20,000). Речь идёт о двух важных use-after-free уязвимостях, которые проявляются при взаимодействии алгоритма СМ с определёнными PHP-объектами. Они приводят к далеко идущим последствиям вроде использования десериализации для удалённого выполнения кода на целевой системе. В статье мы рассмотрим эти уязвимости.

После фаззинга десериализации и анализа интересных случаев мы выделили два доказательства возможности use-after-free уязвимостей. Если вам интересно, как мы к ним пришли, то почитайте материал по ссылке. Один из примеров:

Наверное, вы думаете, что результат будет примерно таким:

В любом случае после исполнения мы видим, что внешний массив (на него ссылается $outer_array ) освобождён, а его zval перезаписан zval’ом $filler2 . И в качестве результата мы получаем bbbb . Возникают следующие вопросы:

  • Почему вообще освобождается внешний массив?
  • Что делает gc_collect_cycles() и действительно ли необходимо вызывать её вручную? Это очень неудобно для удалённого использования, потому что многие скрипты и установки вообще не вызывают эту функцию.
  • Даже если мы сможем вызвать её в ходе десериализации, будет ли работать этот пример?

Похоже, вся магия происходит в функции gc_collect_cycles , которая вызывает сборщик мусора PHP. Нам нужно лучше понять её, чтобы разобраться с этим таинственным примером.

Обратите внимание: нужны базовые знания о внутренностях PHP, управлении памятью и вещах вроде zval’а и подсчёта ссылок. Если вы не знаете, что это, то сначала ознакомьтесь с основами: PHP Internals Book – Basic zval structure и PHP Internals Book – Memory managment.

Zend/zend_gc.c. При каждом уничтожении zval’а, т. е. когда он сбрасывается (unset), применяется алгоритм СМ, который проверяет, массив это или объект. Все остальные типы данных (примитивы) не могут содержать циклические ссылки. Проверка реализована путём вызова функции gc_zval_possible_root . Любой такой потенциальный zval называется root и добавляется в список gc_root_buffer .

Эти шаги повторяются до тех пор, пока не будет выполнено одно из условий:

  • gc_collect_cycles() вызван вручную.
  • Заполнился объём памяти для хранения мусора. Это означает, что в root-буфере сохранено 10 000 zval’ов и сейчас будет добавлен ещё один. Ограничение 10 000 по умолчанию прописано в GC_ROOT_BUFFER_MAX_ENTRIES в заглавной секции Zend/zend_gc.c. Следующий zval снова вызовет gc_zval_possible_root , а тот уже вызовет gc_collect_cycles для обработки и очистки текущего буфера, чтобы можно было сохранять новые элементы.

стандартный для PHP 5.6 .gdbinit, а также кастомную подпрограмму для дампинга содержимого буфера сборщика мусора.

Теперь установим точку прерывания в gc_mark_roots и gc_scan_roots , чтобы посмотреть состояние всех соответствующих счётчиков ссылок.

Нам нужно найти ответ на вопрос: почему освобождается внешний массив? Загрузим php-процесс в gdb, установим точки прерывания и выполним скрипт.

Как видите, после десериализации оба массива (внутренний и внешний) добавлены в буфер сборщика мусора. Если мы продолжим и прервёмся на gc_scan_roots , то получим следующие состояния счётчиков ссылок:

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

появилась в PHP 7.1.0 alpha2 почти сразу после выхода. Получается, что уязвимости подвержены все версии PHP >= 5.3 и PHP php_zip_get_properties . Тем самым мы освобождаем какой-то конкретный элемент. Посмотрите на пример:

Нужно упомянуть, что в нормальных условиях невозможно создать ссылки на zval’ы, которые ещё не десериализованы. Эта полезная нагрузка использует небольшой трюк, позволяющий обойти ограничение:

[. ] i:1;N; [. ] s:8:»filename»;i:1337; [. ] i:1;R:REF_TO_FILENAME; [. ]

Здесь создаётся запись NULL с индексом 1, которая позднее перезаписывается ссылкой на имя файла. Сборщик мусора увидит только “i:1;REF_TO_FILENAME; […] s:8:”filename”;i:1337; […]”. Этот трюк необходим для уверенности в том, что счётчик ссылок целочисленного zval’а “filename” был ослаблен, прежде чем начнут действовать какие-либо побочные эффекты.

Заключение

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

Было интересно понаблюдать за взаимодействием двух совершенно не связанных друг с другом PHP-компонентов: десериализатора и сборщика мусора. Лично я получил море удовольствия и многое узнал, анализируя их поведение. Так что могу порекомендовать вам воспроизвести всё вышесказанное для обучения. Это особенно важно: статья достаточно длинная, но даже в ней я не осветил ряд деталей.

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

Эксперимент подтвердил, что мы можем использовать одну из обсуждённых уязвимостей для удалённого исполнения кода на pornhub.com. Это делает сборщика мусора в PHP интересным кандидатом для атаки.


Сборка мусора zval’ов пошла как-то не так.

Реализация сборки мусора на С++


Автор: Михаил Чащин
Источник: RSDN Magazine #1

Опубликовано: 18.11.2002
Исправлено: 13.03.2005
Версия текста: 1.0

В данной статье мы рассмотрим обобщённую реализацию сборки мусора на С++. Будут обсуждены два конкретных алгоритма сборки мусора – “Mark-Sweep” и “Mark-Compact”, и их реализация. Мы также рассмотрим ограничения, которые накладываются на приложения при использовании сборки мусора, и изменения в компиляторе C++, которые могли бы помочь избежать этих ограничений.

Сборка мусора, или Garbage Collection (сокращённо GC), представляет собой процесс утилизации памяти для повторного её использования. В задачу сборки мусора входит поиск всех объектов, которые более не используются системой, и их удаление с целью повторного использования памяти работающим приложением. Объекты приложения рассматриваются как мусор, если они ни прямо, ни косвенно не доступны работающей программе.

Использование сборки мусора, как одного из вариантов автоматического управления памятью, многими разработчиками в наши дни рассматривается как необходимый шаг к обеспечению надёжности программы, поскольку в этом случае код для работы с памятью собран в одном чётко определённом модуле, а не разбросан в разных частях приложения. В этом случае с одной стороны мы получаем целый ряд преимуществ, в числе которых решение проблемы повисших указателей (dangling pointers) и утечек памяти (memory leaks), но, с другой стороны, мы теряем гибкость, поскольку сборка мусора накладывает некоторые ограничения на разработку приложения.

Читать еще:  Системы сборки проектов

Если сборка мусора не встроена в язык программирования, её очень тяжело использовать. Кроме этого, возможны потери как в скорости, так и в памяти. Поэтому общепризнанным является тот факт, что самого эффективного автоматического управления памятью в приложении можно добиться только в том случае, если это управление поддерживается самим языком программирования. К сожалению, сегодня стандартный C++ эту возможность не поддерживает. Поэтому программистам, желающим использовать сборку мусора, приходится реализовывать тот или иной алгоритм сборки мусора вручную. Самым распространённым вариантом является так называемый подсчёт ссылок. Правда, этот алгоритм содержит крупный недостаток – проблему утилизации цикличных графов.

Надо отметить, что автоматическая сборка мусора не включена в стандарт C++ по той простой причине, что программа, её использующая, будет всегда работать медленнее, чем если бы сборка мусора не использовалась вообще. Поэтому Бьёрном Страуструпом было предложено перепоручить обязанности сборки мусора внешним библиотекам, не затрагивая самого C++, что может позитивно сказаться на производительности приложений, поскольку программист сам может решить, где и когда ему стоит использовать автоматическое управление памятью. Это и является серьёзным отличием С++ от Java – при использовании Java у программистов просто нет выбора.

Сборка мусора логически состоит из двух частей:

  1. Поиск мусора – процесс поиска недостуных для приложения объектов;
  2. Удаление мусора – процесс утилизации памяти для дальнейшего её использования.

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

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

В дальнейшем мы будем называть объекты, с которыми работает сборка мусора, управляемыми (managed) объектах, в отличие от неуправляемых (unmanaged) объектов, которые не подвержены процессу сборки мусора.

Анализ

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

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

Следующий вопрос заключается в поиске объектов внутри периметра, то есть таких объектов, которые доступны косвенно через объекты на периметре. Запрашивая каждый объект на периметре, чтобы он перечислил все свои внутренние указатели на объекты, мы получим часть объектов внутри периметра (первый уровень). Если, в свою очередь, их также опросить обо всех объектах, на которые они имеют ссылки, мы получим ещё один набор объектов внутри периметра. Продолжая так до тех пор, пока существуют косвенные ссылки, мы найдём все объекты внутри периметра. Легко заметить, что объекты внутри периметра образуют граф, который может содержать зацикливающиеся ссылки. Поэтому, во избежание зацикливания, необходимо каким-то образом отличать уже опрошенные объекты от не опрошенных. Это можно сделать либо создав список опрошенных объектов, либо добавлением в объекты специального флага. Мы воспользуемся вторым способом. Установка этого флага будет говорить о том, что объект находится внутри периметра, и что он уже был опрошен о внутренних ссылках. Если мы установим этот флаг и у всех объектов на периметре, то поиск мусора, или объектов вне периметра, сведётся к простой проверке объектов на сброшенность флага. Последнее утверждение подразумевает, что у нас есть возможность перебирать все объекты.

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

Итак, мы имеем следующее решение: все объекты создаются упорядоченно, чтобы их можно было перемещать, уменьшая тем самым фрагментацию памяти. Для каждого объекта существует ровно один smart-указатель, который инкапсулирует создание объекта, подсчёт ссылок, а также включает флаг, необходимый для определения принадлежности объекта к периметру. Все указатели на smart-указатели могут создаваться как угодно, но как только они создаются, они должны увеличивать счётчик ссылок smart-указателя, а при уничтожении соответственно его уменьшать. Поэтому такие указатели лучше всего также сделать smart-указателями (в дальнейшем мы будем называть их дескрипторами).

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

Дизайн

Посмотрим на обобщённый дизайн (generic design) будущей системы. Начнём со smart-указателей. Как уже упоминалось выше, в их обязанность входит подсчёт ссылок, который может быть реализован по-разному, и в нашем случае не влияет на остальную функциональность класса smart-указателей. Поэтому представляется хорошей идеей вынести подсчёт ссылок в отдельный класс. Использование функциональности такого класса в классе smart-указателей возможно несколькими способами. Мы воспользуемся наследованием. Класс подсчёта ссылок должен реализовывать следующие функции:

  • void AddRef() – вызывается при добавлении ссылки на объект;
  • void Release() – вызывается при удалении ссылки на объект;
  • bool active() const – используется сборщиком мусора для определения того, что объект принадлежит периметру, то есть его счётчик не равен нулю.

Примером класса с таким интерфейсом может быть следующий шаблон:

Здесь параметр T шаблона – это тип, который выбирается программистом для переменной, хранящей количество ссылок. Например, если на один объект может существовать огромное количество указателей, то в шаблон лучше всего передать тип unsigned long. Если же нет, то может подойти и unsigned char.

Чтобы иметь возможность перечислять объекты периметра, необходимо уметь перечислять smart-указатели, у которых счётчик ссылок отличен от нуля. Поэтому нужно контролировать процесс создания smart-указателей. Эту функциональность мы также можем вынести в отдельный класс (назовём его SPAllocator), от которого в дальнейшем унаследуем класс smart-указателей. Ниже приведён список функций, которые образуют интерфейс для создания и перечисления smart-указателей:

  • static void* operator new(size_t) – создание smart-указателя;
  • static void operator delete(void*) – удаление smart-указателя;
  • static SPIterator iterator() – возвращает итератор списка smart-указателей.

Класс SPIterator – это вложенный в SPAllocator открытый класс. Прототип шаблона класса SPAllocator приведён в листинге 2.

При создании smart-указателя происходит непосредственное создание объекта. Удаление smart-указателя влечёт за собой удаление объекта. Кроме процедур создания и удаления может понадобиться процедура уплотнения памяти. Поэтому класс для управления жизнью объектов (назовём его ObjectAllocator) должен предоставлять следующие три функции:

  • static void* Allocate(size_t) – возвращает адрес памяти, выделенной для объекта;
  • static void Deallocate(void*) – удаляет объект по заданному адресу памяти;
  • static void Compact() – вызывается для дефрагментации памяти.

Функция Allocate может автоматически вызывать сборку мусора при нехватке памяти, чтобы освободить хотя бы часть ресурсов. В то же время функция Compact должна передвигать объекты в памяти, и, следовательно, должна знать о smart-указателях. Поэтому класс ObjectAllocator – это шаблон, в качестве параметров которого выступают класс сборки мусора и класс smart-указателей (см. ниже). Прототип класса приведён в листинге 3.

Итак, после разделения функциональности класса smart-указателя на непересекающиеся части, мы получаем обобщённый шаблон класса smart-указателя:

где T – тип создаваемого объекта, R – класс, инкапсулирующий подсчёт ссылок (например, UnsafeRefCounter из листинга 1), S – класс-шаблон, отвечающий за создание и перечисление smart-указателей (прототип такого класса – SPAllocator – приведён в листинге 2), GC – класс сборки мусора (см. ниже), W – класс, инкапсулирующий создание объекта (прототип такого класса – ObjectAllocator – приведён в листинге 3).

Чтобы иметь возможность перебирать smart-указатели, нам необходимо абстрагироваться от типов объектов, на которые они указывают, но в то же время иметь к ним доступ. Вынося общую для всех smart-указателей функциональность в родительский класс, мы получаем решение, описанное в листинге 5:

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

Метод выделения и освобождения памяти в Python — автоматический. Пользователь не обязан предварительно выделять или освобождать память, аналогично использованию динамического выделения памяти в таких языках, как C или C ++.
Python использует две стратегии для выделения памяти:

  • Подсчет ссылок
  • Вывоз мусора

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

# Literal 9 — это объект

# Счетчик ссылок объекта 9
# становится 0.

Буквальное значение 9 является объектом. Счетчик ссылок объекта 9 увеличивается до 1 в строке 1. В строке 2 его счетчик ссылок становится равным нулю при разыменовании. Таким образом сборщик мусора освобождает объект.

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

# создать список x

# Ссылочный цикл создан

# здесь, поскольку х содержит ссылку на

Поскольку create_cycle () создает объект x, который ссылается на себя, объект x не будет автоматически освобожден, когда функция вернется. Это приведет к тому, что память, которую использует x, будет удерживаться до вызова сборщика мусора Python.

Способы сделать объект пригодным для сбора мусора

# удалить список из памяти или
# присвоение объекта x None (Null)

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

Автоматическая сборка мусора циклов

Поскольку эталонные циклы требуют вычислительной работы для обнаружения, сборка мусора должна быть запланированной операцией. Python планирует сборку мусора на основе порога выделения объектов и освобождения объектов. Когда количество выделений минус количество освобождений больше порогового значения, запускается сборщик мусора. Можно проверить порог для новых объектов (объекты в Python, известные как объекты поколения 0), импортировав модуль gc и запросив пороги сбора мусора:

# получить текущую коллекцию
# пороги как кортеж

print ( «Garbage collection thresholds:» ,

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

Ручная сборка мусора

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

# Импорт модуля gc

# Возвращает количество
# объектов, которые он собрал
# и освобожден

# Печатает сборщик мусора
# как 0 объект

print ( «Garbage collector: collected» ,

«%d objects.» % collected)

Если создано несколько циклов, то как работает ручной сбор:
Пример:

# создать цикл и на каждой итерации x как словарь
# присвоено 1

# списки очищаются всякий раз, когда полная коллекция или
# коллекция самого высокого поколения (2) запущена

collected = gc.collect() # или gc.collect (2)

print «Garbage collector: collected %d objects.» % (collected)

print «Creating cycles. «

for i in range ( 10 ):

print «Garbage collector: collected %d objects.» % (collected)

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

Ссылка на основную публикацию
Adblock
detector