#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
- 1289 reads
mariyas
Sat, 09/16/2023 - 08:56
Permalink
добавлено: циклические ссылки
добавлено: циклические ссылки