#7. 6 php Алгоритм сбора мусора. Циклические ссылки
Primary tabs
Алгоритм сбора мусора
Для того, чтобы определить в какой момент нужно вызывать деструктор объекта, каждый объект содержит скрытое поле, хранящее счетчик ссылок. Каждый раз, когда в программе появляется новая ссылка на объект, это значение счетчика увеличивается на единицу, а при удалении ссылки — уменьшается на единицу. Если в какой-то момент обнаружено, что значение счетчика обнулилось, объект удаляется.
При удалении объекта происходит следующее:
- удаляются все ссылки, которые содержит сам этот объект. Если в процессе этой процедуры какой-либо подчиненный объект теряет последнюю ссылку, он также будет удален и т.д.;
- вызывается деструктор объекта;
- освобождается занимаемая память.
Например, пусть вместе с именем животного в объекте класса Animal
мы будем хранить также список его детей. Для этого в примере 1 добавлено свойство children
и метод add_child
в описание класса.
Пример 1. Удаление объекта, содержащего ссылки на другие объекты
<HTML> <HEAD> <TITLE> Удаление объекта, содержащего ссылки на другие объекты </TITLE> </HEAD> <BODY> <CENTER> <H1> Удаление объекта, содержащего ссылки на другие объекты. </H1> <?php class Animal { private $name; private $children; public function __construct($text) { $this->name = $text; $this->children = []; } public function set_name($text) { $this->name = $text; } public function get_name() { return $this->name; } public function add_child($child) { $this->children[] = $child; } public function __destruct() { echo "Объект ", $this->name, " уничтожен.<BR>"; } } $lion = new Animal("Бонифаций"); $lion->add_child(new Animal("Симба")); $lion = null; echo "Конец программы.<BR>"; ?> </CENTER> </BODY> </HTML>
Итак, мы присвоили переменной $lion
ссылку на объект с именем "Бонифаций", затем с помощью метода add_child
добавили ему одного ребенка — объект "Симба", и после этого обнулили переменную $lion
.
Результат выполнения примера:
Мы видим, что при обнулении единственной ссылки на объект "Бонифаций" сначала вызывается деструктор самого этого объекта, а затем и деструктор подчиненного объекта "Симба".
Проблема циклических ссылок
возникает, когда два объекта прямо или косвенно ссылаются друг на друга. В примере 2 мы создаем два объекта класса Animal
— "Бонифаций" и "Симба":
$father = new Animal("Бонифаций"); $child = new Animal("Симба");
Затем при помощи функции add_child
сохраняем в свойстве children
объекта "Бонифаций" ссылку на объект "Симба":
$father->add_child($child);
А при помощи функции set_father
сохраняем в свойстве father
объекта "Симба" ссылку на объект "Бонифаций":
$child->set_father($father);
И наконец, перезапишем переменные, ссылающиеся на объекты:
$father = $child = null;
Пример 2. Циклические ссылки
<HTML> <HEAD> <TITLE> Циклические ссылки </TITLE> </HEAD> <BODY> <CENTER> <H1> Циклические ссылки. </H1> <?php class Animal { private $name; private $children; private $father; public function __construct($text) { $this->name = $text; $this->children = []; } public function set_name($text) { $this->name = $text; } public function get_name() { return $this->name; } public function add_child($child) { $this->children[] = $child; } public function set_father($father) { $this->father = $father; } public function __destruct() { echo "Объект ", $this->name, " уничтожен.<BR>"; } } $father = new Animal("Бонифаций"); $child = new Animal("Симба"); $father->add_child($child); $child->set_father($father); $father = $child = null; echo "Конец программы.<BR>"; ?> </CENTER> </BODY> </HTML>
Запустив пример, мы увидим, что оба объекта будут разрушены уже после завершения работы скрипта (рис. 2). Несмотря на то, что после строки $father = $child = null
в программе отсутствует доступ к ним, память, занимаемая объектами, не освобождается. Это происходит как раз по причине циклических ссылок. Объекты "Бонифаций" и "Симба" ссылаются друг на друга, поэтому даже при удалении всех остальных ссылок, счетчик каждого из них равен 1.
В данном примере "длина цикла" равна двум. Однако та же самая ситуация возникает и в более сложных случаях, когда "А" ссылается на "B", "B" ссылается на "С", "C" ссылается на "А" и т.п. Если в программе есть циклические ссылки, алгоритм сбора мусора, описанный выше, не срабатывает.
Начиная с PHP 5.3, в сборщик мусора PHP внедрен синхронный механизм сбора циклических ссылок. Все объекты, генерирующие ссылки, помещаются в специальный буфер, размер которого составляет 10000. При заполнении буфера стартует процедура сборки мусора, в результате которой алгоритм корректирует счетчики. Объекты, чьи счетчики стали равны нулю, удаляются. По умолчанию сборщик мусора включен. Если скрипт работает короткое время и потребляет мало памяти, можно увеличить производительность за счет отключения сборщика мусора, установив значение директивы zend.enable_gc в конфигурационном файле php.ini в значение off.
- Log in to post comments
- 708 reads
mariyas
Sat, 09/16/2023 - 08:56
Permalink
добавлено: циклические ссылки
добавлено: циклические ссылки