Рубрики
Uncategorized

Механизм сборки мусора PHP – базовые знания подсчета ссылок (5.3)

Автор оригинала: David Wong.

Сборка мусора, называемая GC, была выпущена до версии 5.3, чтобы просто определить, было ли значение параметра zval переменной 0, если оно было, не до конца процесса (скрывая риск переполнения памяти переменной).

Если вы установили Xdebug, вы можете вызвать функцию debug_debug_zval() Отображает значения “refcount” и “is_ref”.

Базовые знания по подсчету ссылок

1. Контейнер переменной zval:

тип
ценность
is_referred Является ли значение bool значением, определяющим принадлежность переменной к ссылочному набору? В контейнере переменных zval также имеется внутренний механизм подсчета ссылок для оптимизации использования памяти
пересчет Количество переменных (также известных как символы), указывающих на этот контейнер переменных zval Все символы существуют в таблице символов, где каждый символ имеет область действия, эти основные сценарии (например, сценарии, запрашиваемые через браузеры) и каждая функция или метод имеют область действия.

Когда переменной присваивается постоянное значение, создается контейнер переменной zval.

1. Создайте новый контейнер zval

php
$a = "new string";
?>

Ссылаясь на приведенное выше определение, они являются:

Сгенерированные контейнеры переменных, где:

  1. Введите строку
  2. Значение новой строки
  3. is_ref false
  4. Пересчет 1

2,Добавить счетчик ссылок zval

Присвоение одной переменной другой увеличивает количество пересчетов.

  1. Введите строку
  2. Значение новой строки
  3. is_ref верно
  4. Пересчет 2

Количество ссылок составляет 2 Поскольку один и тот же контейнер переменных связан с переменной a и переменной b, PHP не копирует сгенерированный контейнер переменных, когда в этом нет необходимости. Контейнеры переменных уничтожаются, когда значение “refcount” становится равным нулю. Когда какая-либо переменная, связанная с контейнером переменных, покидает его область действия (например, когда заканчивается выполнение функции) или когда для переменной вызывается функция unset (), “refcount” уменьшается на 1.

3. Сокращение Количества Ссылок



a: (refcount=3, is_ref=0)='new string'
a: (refcount=1, is_ref=0)='new string'

Если мы сделаем это сейчас сбросить($a) ; Контейнер, содержащий тип и значение, удаляется из памяти.

4. Типы Соединений

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

 'life', 'number' => 42 );
xdebug_debug_zval( 'a' );
?>

выход

a: (refcount=1, is_ref=0)=array (
   'meaning' => (refcount=1, is_ref=0)='life',
   'number' => (refcount=1, is_ref=0)=42
)

посмотри и скажи

Тремя контейнерами переменных zval являются: a, значение и число. Правило увеличения и уменьшения “рефкоунта” такое же, как и упомянутое выше. Затем мы добавляем еще один элемент в массив и устанавливаем его значение равным значению существующего элемента в массиве:

Добавьте существующий элемент в массив

 'life', 'number' => 42 );
$a['life'] = $a['meaning'];
xdebug_debug_zval( 'a' );
?>

выход

a: (refcount=1, is_ref=0)=array (
   'meaning' => (refcount=2, is_ref=0)='life',
   'number' => (refcount=1, is_ref=0)=42,
   'life' => (refcount=2, is_ref=0)='life'
)

Есть картинки и факты.

Из приведенной выше выходной информации Xdebug мы видим, что исходные элементы массива и вновь добавленные элементы массива связаны с одним и тем же “refcount” 2 Контейнер переменной zval Xdebug. Хотя вывод Xdebug показывает два значения ‘жизнь’ Контейнер переменной zval на самом деле один и тот же. функция xdebug_debug_zval() Эта информация не отображается, но вы можете увидеть ее, отобразив информацию об указателе памяти.

Удаление элемента в массиве аналогично удалению переменной из области видимости. После удаления значение “refcount” контейнера, в котором находится элемент, уменьшается. Аналогично, когда значение “refcount” равно 0, контейнер переменной удаляется из памяти. Другой пример может быть показан ниже.

 'life', 'number' => 42 );
$a['life'] = $a['meaning'];
unset( $a['meaning'], $a['number'] );
xdebug_debug_zval( 'a' );
?>

выход

a: (refcount=1, is_ref=0)=array (
   'life' => (refcount=1, is_ref=0)='life'
)

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

Добавьте массивы к себе в качестве элемента

выход

a: (refcount=2, is_ref=1)=array (
   0 => (refcount=1, is_ref=0)='one',
   1 => (refcount=2, is_ref=1)=...
)

посмотри и скажи

Вы можете видеть, что переменная массива (a) также является вторым элементом массива (1), указывающим на контейнер переменной “refcount” как 2 。 “…” в выводе выше указывает на то, что произошла рекурсивная операция, что явно означает, что “…” в данном случае указывает на исходный массив.

Как и раньше, вызов unset для переменной удаляет символ и уменьшает количество ссылок в контейнере переменной, на который он указывает, на 1. Итак, если мы вызовем unset для переменной $a после выполнения приведенного выше кода, то количество ссылок на контейнер переменных, на которые ссылается переменная $a и элемент массива “1”, уменьшится на 1, с “2” до “1”.

выход

(refcount=1, is_ref=1)=array (
   0 => (refcount=1, is_ref=0)='one',
   1 => (refcount=1, is_ref=1)=...
)

посмотри и скажи

2. Проблемы с Очисткой.

Хотя в области видимости больше нет символа, указывающего на эту структуру (то есть контейнер переменных), поскольку элемент массива “1” по-прежнему указывает на сам массив, контейнер нельзя очистить. Поскольку на него нет другого символа, указывающего на него, у пользователя нет возможности очистить структуру, что приводит к утечке памяти. К счастью, PHP очистит эту структуру данных в конце выполнения скрипта, но она будет потреблять много памяти до того, как PHP будет очищен. Это часто происходит, если вы хотите реализовать алгоритм анализа или сделать что-то еще, например, чтобы ребенок указывал на своего родителя. Конечно, то же самое происходит с объектами, что с большей вероятностью произойдет с объектами, потому что на них всегда имеются неявные ссылки.

Это нормально, если это происходит только один или два раза, но если есть тысячи или даже сотни тысяч утечек памяти, это, очевидно, большая проблема. Такие проблемы часто возникают в длительно работающих сценариях, таких как демоны, где запросы по существу не завершаются, или в больших наборах модульных тестов. Примеры последних: Проблемы могут возникнуть при модульном тестировании компонентов шаблонов огромной библиотеки компонентов eZ (хорошо известной библиотеки PHP). Иногда для теста может потребоваться 2 ГБ памяти, а у тестового сервера может быть не так много памяти.

Руководство по PHP

Оригинал: “https://developpaper.com/php-garbage-collection-mechanism-basic-knowledge-of-reference-counting-5-3/”