Какая функция gc_collect_cycles полезна?

Может кто-нибудь объяснить, при каких обстоятельствах gc_collect_cycles функция может быть полезна? Должен ли он быть вызван до того, как произойдет существенное использование памяти?

Ответы

Ответ 1

В PHP включен "сборщик мусора" по умолчанию. Он используется для освобождения памяти, используемой "мусором". gc_collect_cycles() принудительно собирает любые существующие циклы мусора. Он возвращает количество собранных (освобожденных) циклов (объекты, значения переменных...). Enabled Garbage Collector периодически вызывает эту функцию, чтобы освободить ресурсы. В большинстве случаев PHP script живет очень короткое время. В этом случае вся мусор будет уничтожен в конце работы без сбора мусора.

Иногда это необходимо для управления GC вручную:

  • gc_disable() может ускорить некоторые длительные операции, но также приводит к некоторым накладным расходам памяти.
  • gc_collect_cycles() может использоваться для указания правильных моментов GC.

Еще одна причина использования gc_collect_cycles() - отладки. Предположим, вы хотите узнать, каково потребление памяти для некоторого блока кода с помощью memory_get_usage(). Сначала вам нужно отключить GC, в другом месте вы получите неправильные результаты. После этого вы хотите отделить время, затраченное GC и вашим приложением. Поэтому вызовите gc_collect_cycles() и измерьте тайминги/память до и после.

Маленький пример:

class A {
  public $ref;
  public $name;

  public function __construct($name) {
    $this->name = $name;
    echo($this->name.'->__construct();'.PHP_EOL);
  }

  public function __destruct() {
    echo($this->name.'->__destruct();'.PHP_EOL);
  }
}

gc_disable();

$a1 = new A('$a1');
$a2 = new A('$a2');

$a1->ref = $a2;
$a2->ref = $a1;

$b = new A('$b');
$b->ref = $a1;

echo('$a1 = $a2 = $b = NULL;'.PHP_EOL);
$a1 = $a2 = $b = NULL;
echo('gc_collect_cycles();'.PHP_EOL);
echo('// removed cycles: '.gc_collect_cycles().PHP_EOL);
echo('exit();'.PHP_EOL);

Будет выводиться:

$a1->__construct();
$a2->__construct();
$b->__construct();
$a1 = $a2 => $b = NULL;
$b->__destruct();
gc_collect_cycles();
$a2->__destruct();
$a1->__destruct();
// removed cycles: 4

Это означает, что только $b был уничтожен, когда его спросили. Другие $a1 и $a2 имеют циклические ссылки, а свойства name также потребляют память. Два объекта + две строки = 4 (удалены с помощью gc_collect_cycles()).