Механизм сборки мусора php — это знакомый, но незнакомый контент для PHPer. Так как же php реализует утилизацию ненужной памяти?
Внутренняя структура хранения переменных php
Прежде всего, вам все же нужно усвоить базовые знания, чтобы облегчить понимание содержания сборки мусора. Всем известно, что php написан на C, поэтому внутренняя структура хранения переменных php также будет связана с языком C, то есть структура zval:
struct _zval_struct {
union {
long lval;
double dval;
struct {
char *val;
int len;
} str;
HashTable *ht;
zend_object_value obj;
} value; //变量value值
zend_uint refcount__gc; //引用计数内存中使用次数,为0删除该变量
zend_uchar type; //变量类型
zend_uchar is_ref__gc; //区分是否是引用变量
};
Из содержимого приведенной выше структуры видно, что каждая переменная php будет определена变量类型
,value值
,引用计数次数
и是否是引用变量
четыре части
Примечание: Приведенная выше структура zval является структурой после версии php5.3.До php5.3 не было нового механизма сборки мусора, то есть GC, поэтому не было имени._gc
; После версии php7 структура zval была переписана из-за проблем с производительностью, что здесь больше не описано
Принципы подсчета ссылок
Поняв внутреннюю структуру хранения переменных php, давайте разберемся с принципами, связанными с назначением переменных php и механизмом ранней сборки мусора.
переменный контейнер
Немассивные и объектные переменные
Каждый раз, когда константа присваивается переменной, создается контейнер переменных.
Пример:
$a = '许铮的技术成长之路';
xdebug_debug_zval('a')
результат:
a: (refcount=1, is_ref=0)='许铮的技术成长之路'
массив и объектные переменные
Сгенерирует переменный контейнер с количеством элементов + 1
Пример:
$b = [
'name' => '许铮的技术成长之路',
'number' => 3
];
xdebug_debug_zval('b')
результат:
b: (refcount=1, is_ref=0)=array ('name' => (refcount=1, is_ref=0)='许铮的技术成长之路', 'number' => (refcount=1, is_ref=0)=3)
Принцип присвоения (техника копирования при записи)
Разобравшись с присваиванием констант, давайте подумаем о присваивании между переменными с точки зрения памяти.
Пример:
$a = [
'name' => '许铮的技术成长之路',
'number' => 3
]; //创建一个变量容器,变量a指向给变量容器,a的ref_count为1
$b = $a; //变量b也指向变量a指向的变量容器,a和b的ref_count为2
xdebug_debug_zval('a', 'b');
$b['name'] = '许铮的技术成长之路1';//变量b的其中一个元素发生改变,此时会复制出一个新的变量容器,变量b重新指向新的变量容器,a和b的ref_count变成1
xdebug_debug_zval('a', 'b');
результат:
a: (refcount=2, is_ref=0)=array ('name' => (refcount=1, is_ref=0)='许铮的技术成长之路', 'number' => (refcount=1, is_ref=0)=3)
b: (refcount=2, is_ref=0)=array ('name' => (refcount=1, is_ref=0)='许铮的技术成长之路', 'number' => (refcount=1, is_ref=0)=3)
a: (refcount=1, is_ref=0)=array ('name' => (refcount=1, is_ref=0)='许铮的技术成长之路', 'number' => (refcount=1, is_ref=0)=3)
b: (refcount=1, is_ref=0)=array ('name' => (refcount=1, is_ref=0)='许铮的技术成长之路1', 'number' => (refcount=1, is_ref=0)=3)
Следовательно, когда переменная a присваивается переменной b, новый контейнер переменных не генерируется немедленно, а переменная b указывает на контейнер переменных, на который указывает переменная a, то есть память является «разделяемой»; и когда один из элементов переменной b Копирование контейнера переменной фактически происходит только тогда, когда оно изменяется, т.е.写时复制技术
Счетчик ссылок очищается до 0
Когда счетчик ref_count контейнера переменных сбрасывается до 0, это означает, что контейнер переменных будет уничтожен и реализовано восстановление памяти.php5.3版本之前的垃圾回收机制
Пример:
$a = "许铮的技术成长之路";
$b = $a;
xdebug_debug_zval('a');
unset($b);
xdebug_debug_zval('a');
результат:
a: (refcount=2, is_ref=0)='许铮的技术成长之路'
a: (refcount=1, is_ref=0)='许铮的技术成长之路'
Утечка памяти из-за циклической ссылки
Однако в механизме сборки мусора до версии php5.3 есть лазейка, то есть когда дочерний элемент внутри массива или объекта ссылается на свой родительский элемент, и если родительский элемент в это время удаляется, переменная container удаляться не будет, т.к. его дочерние элементы по-прежнему указывают на контейнер переменных, но так как символов, указывающих на контейнер переменных, во всех скоупах нет, их невозможно очистить, поэтому будет происходить утечка памяти, пока не завершится выполнение скрипта
Пример:
$a = array( 'one' );
$a[] = &$a;
xdebug_debug_zval( 'a' );
Так как этот пример не годится для вывода результатов, он представлен графиком, как показано на рисунке:
Пример:
unset($a);
xdebug_debug_zval('a');
Как показано на рисунке:
Новый механизм сбора мусора
После версии php5.3 был введен механизм корневого буфера, то есть при старте php по умолчанию устанавливается корневой буфер с заданным количеством zval'ов (по умолчанию 10000). ссылка, он поместит его в корневой буфер. Когда корневой буфер достигнет указанного числа в файле конфигурации (по умолчанию 10000), будет выполнена сборка мусора, чтобы решить проблему утечки памяти, вызванную циклическими ссылками.
Руководство по распознаванию нежелательной почты
1. Если счетчик ссылок уменьшится до нуля, переменный контейнер будет очищен (освобожден), а не мусор
2. Если счетчик ссылок zval уменьшится и все еще больше 0, он войдет в цикл мусора. Во-вторых, в цикле мусора выясните, какие части являются мусором, проверив, уменьшился ли счетчик ссылок на 1, и проверив, какие контейнеры переменных имеют нулевые ссылки.
Суммировать
Механизм сбора мусора:
1. Основан на механизме подсчета ссылок php (только этот механизм был доступен до php5.3)
2. При этом используется механизм корневого буфера.Когда PHP находит, что есть zval с циклической ссылкой, он помещает его в корневой буфер.Когда корневой буфер достигает указанного числа в конфигурационном файле, он будет выполнять сборку мусора, что решает проблему утечки памяти, вызванную циклическими ссылками (этот механизм был представлен в php5.3).