Maison  >  Article  >  développement back-end  >  Analyse du mécanisme de récupération de place PHP7 (GC)

Analyse du mécanisme de récupération de place PHP7 (GC)

Guanhui
Guanhuiavant
2020-05-20 11:17:575639parcourir

Analyse du mécanisme de récupération de place PHP7 (GC)

Mécanisme de collecte des déchets

Le mécanisme de collecte des déchets est un schéma d'allocation de stockage dynamique. Il libère automatiquement les blocs de mémoire alloués qui ne sont plus nécessaires au programme. Le processus de récupération automatique de la mémoire est appelé garbage collection. Le mécanisme de récupération de place permet aux programmeurs de ne pas trop se soucier de l'allocation de mémoire du programme, afin qu'ils puissent consacrer plus d'énergie à la logique métier. Parmi les différents langages populaires aujourd'hui, le mécanisme de garbage collection est une caractéristique commune de la nouvelle génération de langages.

Génération de déchets

Les types complexes en PHP7, tels que les chaînes, les tableaux, les objets, etc., ont un gc dans l'en-tête. est utilisé pour prendre en charge la collecte des déchets. Lorsqu'une variable est attribuée ou transférée, le numéro de référence de la valeur sera augmenté lorsque la variable est libérée par unset, return, etc., le numéro de référence sera soustrait après la soustraction, si le refcount devient 0, le la valeur sera libérée directement. Il s’agit du processus de recyclage de base des variables.

Cependant, il existe un problème que ce mécanisme ne peut pas résoudre, à savoir le problème des références circulaires.

Qu'est-ce qu'une référence circulaire ? En termes simples, la valeur stockée dans la variable fait référence à la variable elle-même. Cette comparaison se produit souvent avec des variables de types tableau et objet.

Parlons d'abord des références, c'est-à-dire du type zend_reference. Il s'agit d'un nouveau type de variable en PHP7 Lorsque l'opération "&" est utilisée sur une variable, une nouvelle structure intermédiaire zend_reference sera créée. La structure pointera en fait vers la structure de valeur correspondante.

Par exemple :

// 当进行如下赋值操作时
$a = 'hello'; // $a -> zend_string
$b = $a; // $b,$a -> zend_string
$c = &$b; // $c,$b -> zval(type = IS_REFERENCE, refcount = 2) -> zend_string

finira par devenir comme ceci :

Analyse du mécanisme de récupération de place PHP7 (GC)

C'est-à-dire que le zval de $b et $c passe par au milieu La structure zend_reference pointe alors vers la zend_string finale.

Retour à la question des références circulaires, voici un exemple de références circulaires de tableau :

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

Après avoir utilisé l'opération &, la variable a devient un type référence et le nombre de références refcount est 2 , et une valeur est attribuée à l'élément à l'intérieur de lui-même, c'est-à-dire que la variable a devient une référence à elle-même.

Les détails sont les suivants :

Analyse du mécanisme de récupération de place PHP7 (GC)

Une fois désarmé, il deviendra comme l'image ci-dessous :

Analyse du mécanisme de récupération de place PHP7 (GC)

C'est-à-dire que le type zval où se trouve $a est devenu IS_UNDEF et le nombre de références de la structure zend_reference est réduit de 1, mais est toujours supérieur à 0. À ce stade, cette partie de la structure devient un déchet. Si cela n'est pas traité, cela peut provoquer une fuite de mémoire. Ici, vous avez besoin du garbage collector pour collecter cette partie dans le tampon, puis la recycler.

Processus de recyclage

Si le refcount d'une variable est supérieur à 0 après sa réduction, PHP n'effectuera pas immédiatement l'identification des déchets et le recyclage sur cette variable, mais le fera placez plutôt un Dans le tampon, une fois le tampon plein (10 000 valeurs), il sera traité uniformément. Ce qui est ajouté au tampon est le gc dans la variable zend_value. Actuellement, les déchets n'apparaîtront que sous deux types : les tableaux et les objets. . Dans le cas des tableaux, comme cela a été introduit, dans le cas des objets, les attributs des membres font référence à l'objet lui-même. Dans d'autres types, les membres dans les variables font référence aux variables elles-mêmes, donc le garbage collection se fera uniquement. traiter ces deux types de variables.

La structure de gc zend_refcounted_h est la suivante :

typedef struct _zend_refcounted_h {
    uint32_t         refcount; // 记录 zend_value 的引用数
    union {
        struct {
            zend_uchar    type,  // zend_value的类型, 与zval.u1.type一致
            zend_uchar    flags, 
            uint16_t      gc_info // GC信息,记录在 gc 池中的位置和颜色,垃圾回收的过程会用到
        } v;
        uint32_t type_info;
    } u;
} zend_refcounted_h;

Une variable ne peut être ajoutée au tampon qu'une seule fois Afin d'éviter des ajouts répétés, zend_refcounted_h.gc_info sera défini sur GC_PURPLE après le. La variable ajoutée, qui est marquée en violet, ne sera pas insérée à plusieurs reprises à l'avenir.

Le tampon de récupération est une liste chaînée bidirectionnelle. Lorsque le tampon est plein, le processus de vérification des déchets sera lancé : parcourir le tampon, parcourir tous les membres de la variable actuelle, puis réduire le nombre de références du tampon. membre par 1 (si le membre est toujours s'il contient des sous-membres, il sera également parcouru de manière récursive, c'est-à-dire un parcours en profondeur en premier), et enfin la référence de la variable actuelle sera vérifiée si elle est réduite à 0. , c'est une poubelle. Le principe de base de cet algorithme est le suivant : les déchets sont causés par les membres se référant à eux-mêmes, puis réduisez les références à tous les membres. S'il s'avère que le refcount de la variable finale elle-même devient 0, cela signifie que toutes ses références proviennent de la sienne. membres, c'est-à-dire ailleurs. Si vous ne l'utilisez plus, c'est un déchet et il faut le recycler. Sinon, cela signifie qu'il ne s'agit pas d'un déchet et qu'il doit être supprimé du tampon. Le processus spécifique est le suivant :

(1) Commencez à parcourir à partir des racines de la liste chaînée du tampon, marquez la valeur actuelle en gris (zend_refcounted_h.gc_info est défini sur GC_GREY), puis effectuez d'abord une profondeur parcours des membres de la valeur actuelle, et Le refcount de la valeur membre est réduit de 1 et est également marqué en gris

;

(2) Parcourez à plusieurs reprises la liste chaînée du tampon et vérifiez si la référence de valeur actuelle est 0. Si elle est 0, cela signifie qu'il s'agit bien d'une poubelle. Marquez-la comme blanche (GC_WHITE). Si ce n'est pas 0, cela exclut. toutes les références de ses propres membres. Cela signifie peut-être qu'il y a des références externes et ce n'est pas une poubelle pour le moment, car le refcount des membres est réduit de 1 à l'étape (1), il doit être restauré à nouveau, un. une traversée approfondie de tous les membres est effectuée, le nombre de références des membres est augmenté de 1 et marqué comme Noir ;

(3) Parcourez à nouveau la liste chaînée du tampon et supprimez les nœuds non GC_WHITE de la liste chaînée racines. toutes les listes chaînées de racines seront de véritables déchets, et finalement les déchets seront effacés.

Tutoriels recommandés : "PHP7" "Tutoriel PHP"

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