Maison >développement back-end >PHP7 >Explication détaillée du mécanisme de récupération de place PHP7 (avec organigramme complet du traitement GC)

Explication détaillée du mécanisme de récupération de place PHP7 (avec organigramme complet du traitement GC)

藏色散人
藏色散人avant
2020-08-25 17:49:295082parcourir

Collecte des déchets :

appelé GC. Comme son nom l’indique, cela signifie réutiliser les déchets.
Avant de parler du mécanisme de récupération de place, abordons d’abord les fuites de mémoire.

Tutoriel recommandé : "PHP7"

Fuite de mémoire :

Une explication en image par un grand dieu au goût prononcé :

Le sens général est que si vous demandez un terrain et faites caca pendant un certain temps, mais si vous ne le nettoyez pas après avoir fait caca, le terrain sera considéré comme un déchet. Plus le terrain est utilisé, moins il y en aura, et le pays final sera plein de merde. En dernière analyse, pensez à le retourner après utilisation. Dans une certaine mesure, le mécanisme de collecte des déchets est utilisé pour essuyer les fesses.

Mécanisme de récupération de place en langage C :

Si vous avez utilisé le langage C, la façon de demander de la mémoire est malloc ou calloc. Ensuite, après avoir utilisé cette mémoire, ne le faites pas. oubliez-le. Utilisez la fonction gratuite pour le libérer. Il s'agit d'un garbage collection manuel. Cette méthode est généralement utilisée par les maîtres.

Qu'est-ce que le mécanisme automatique de récupération de place de PHP ?

Réfléchissons d'abord à cette question comme celle-ci. Nous savons tous que PHP est implémenté en langage C. Réfléchissez à la façon d'utiliser le langage C pour implémenter des statistiques et publier une variable. Comment le langage C implémente-t-il une variable ? Depuis le moment où elle est déclarée jusqu'à la fin lorsque personne ne l'utilise, la mémoire occupée par la variable est libérée ( est récupérée ).

Il existe deux algorithmes de base pour la gestion de la mémoire PHP :
L'un est le comptage de références et l'autre est la copie sur écriture

Lors de la déclaration d'une variable PHP , C Le langage génère une struct (structure) appelée zval en bas, comme suit :

zval {
string "a" //变量的名字是a
value zend_value //变量的值,联合体
type string //变量是字符串类型
}

zval struct structure

(1) Enregistrez le nom de la variable php $a
( 2) Type de variable de php $a
(3) union zend_value de la variable php $a

Si une valeur est assignée à la variable , telle que "hello world", alors Le langage C est en bas Générer une union (union) appelée zend_value

zend_value {
string "hello world" //值的内容
refcount 1 //引用计数
}

l'union (union) de zend_value

(1) Enregistrez la valeur de la variable de php $a hello world
(2) Enregistrez le nombre de références à la variable php $a

Voir la structure de la structure zval et zend_value Si l'intervieweur vous demande pourquoi la variable php peut enregistrer la chaîne "123" et le numéro. 123, vous savez quoi faire Avez-vous répondu ? Le point clé est que zval contient le type de la variable. Lorsqu'il s'agit d'une chaîne 123, le type est une chaîne et la valeur pointe vers "123" lorsqu'il s'agit d'un entier 123, le type de zval est int et la valeur. est 123.

Qu'est-ce que le comptage de références ?

Code analyse réelle du nombre de références de variables php

$a = 'hello,world';
echo xdebug_debug_zval( 'a');//refcount=1
$b = $a;
echo xdebug_debug_zval( 'a'); //$b引用$a,故变量a,refcount=2
$c = $a;
echo xdebug_debug_zval( 'a'); //$c引用$a,故变量a,refcount=3
unset( $c );
echo xdebug_debug_zval( 'a');//删除了$c的引用,故变量a,refcount=2

Résultats d'exécution :

a:
(refcount=1, is_ref=0)string 'bonjour , monde' (longueur=11)
a:
(refcount=2, is_ref=0)string 'hello,world' (longueur=11)
a:
(refcount=3, is_ref = 0)chaîne 'bonjour, monde' (longueur=11)
a:
(refcount=2, is_ref=0)chaîne 'bonjour, monde' (longueur=11)

Qu'est-ce que copier ?

$a = 'hello';
$b = $a;//$a赋值给$b的时候,$a的值并没有真的复制了一份
echo xdebug_debug_zval( 'a');//$a的引用计数为2
$a = 'world';//当我们修改$a的值为123的时候,这个时候就不得已进行复制,避免$b的值和$a的一样
echo xdebug_debug_zval( 'a');///$a的引用计数为1

Résultat de l'exécution :

a :
(refcount=2, is_ref=0)string 'hello' (length=5)
a :
(refcount=1, is_ref=0)string 'world' (length=5)

En fait, lorsque vous attribuez $a à $b, la valeur de $a ne correspond pas a vraiment fait une copie. C'est extrêmement irrespectueux de la complexité de la mémoire et du temps. L'ordinateur pointe simplement $b sur la valeur de $a. C'est ce qu'on appelle rapide et économique. Alors, quand la réplication a-t-elle réellement lieu ? Autrement dit, lorsque nous modifions la valeur de $a à 123, nous devons la copier à ce moment-là pour éviter que la valeur de $b soit la même que celle de $a.

Deux points clés sont expliqués à travers des cas simples : le comptage de références et la copie sur écriture.

Mécanisme de récupération de place :

Lorsqu'un zval n'est pas défini, ou lorsqu'il est à court d'une fonction (c'est-à-dire une variable locale), etc., il se produira dans de nombreux endroits. zval et zend_value sont déconnectés. À ce stade, ce que le moteur zend doit détecter, c'est si le refcount de zend_value est 0. S'il est 0, il libérera directement le contenu. Si le recomptage de zend_value n'est pas 0, la valeur ne peut pas être libérée, mais cela ne signifie pas que la zend_value est innocente, car la zend_value peut toujours être une poubelle.

(1) Lorsque le refcount de la variable php $a=0, la variable $a sera récupérée
(2) Lorsque le refcount de la variable php $a>0, la variable $ aMais elle peut aussi être considérée comme une poubelle

Quel genre de situation fera que le refcount de zend_value ne sera pas 0, mais cette zend_value est une poubelle ?

$arr = [ 1 ];
$arr[] = &$arr;
unset( $arr );

这种情况下,zend_value不会能释放,但也不能放过它,不然一定会产生内存泄漏,所以这会儿zend_value会被扔到一个叫做垃圾回收堆中,然后zend引擎会依次对垃圾回收堆中的这些zend_value进行二次检测,检测是不是由于上述两种情况造成的refcount为1但是自身却确实没有人再用了,如果一旦确定是上述两种情况造成的,那么就会将zend_value彻底抹掉释放内存。

垃圾回收发生在什么时候?

有些同学可能有疑问,就是php不是运行一次就销毁了吗,我要gc有何用?并不是的,首先当一次fpm运行完毕后,最后一定还有gc的,这个销毁就是gc;其次是,内存都是即用即释放的,而不是攒着非得到最后,你想想一个典型的场景,你的控制器里的某个方法里用了一个函数,函数需要一个巨大的数组参数,然后函数还需要修改这个巨大的数组参数,你们应该是函数的运行范围里面修改这个数组,所以此时会发生写时拷贝了,当函数运行完毕后,就得赶紧释放掉这块儿内存以供给其他进程使用,而不是非得等到本地fpm request彻底完成后才销毁。

(1)fpm运行完毕后,最后一定会gc的
(2)运行过程中,也会gc的,内存都是即用即释放的,而不是攒着非得到最后gc

GC处理完整流程图

 

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer