Maison > Article > développement back-end > En savoir plus sur le mécanisme de récupération de place de PHP
(Tutoriel recommandé : Tutoriel vidéo PHP)
Chaque variable PHP existe dans un conteneur de variables appelé zval.
Un conteneur de variable zval, en plus du type et de la valeur de la variable, comprend également deux octets d'informations supplémentaires.
Le premier est is_ref, qui est une valeur booléenne utilisée pour identifier si cette variable appartient à la collection de référence. Grâce à cet octet, le moteur PHP peut distinguer les variables ordinaires des variables de référence. Puisque PHP permet aux utilisateurs d'utiliser des références personnalisées en utilisant &, il existe également un mécanisme de comptage de références interne dans le conteneur de variables zval pour optimiser l'utilisation de la mémoire.
Le deuxième octet supplémentaire est refcount, qui représente le nombre de variables pointant vers ce conteneur de variables zval.
Tous les symboles existent dans une table de symboles, où chaque symbole a une portée, et le script principal (par exemple : un script demandé via le navigateur) et chaque fonction ou méthode ont également une portée.
Lorsqu'une variable reçoit une valeur constante, un conteneur de variable zval sera généré
Si Xdebug est installé, vous pouvez visualiser ces deux via xdebug_debug_zval()
<?php $a = "new string"; xdebug_debug_zval('a'); //结果 a: (refcount=1, is_ref=0)='new string'
L'attribution d'une variable à une autre variable augmentera le nombre de références
<?php $a = "new string"; $b = $a; xdebug_debug_zval( 'a' ); //结果 a: (refcount=2, is_ref=0)='new string'
Utilisez unset() pour réduire le nombre de références
Le conteneur de variable contenant le type et la valeur sera supprimé de la mémoire Supprimer
<?php $a = "new string"; $c = $b = $a; xdebug_debug_zval( 'a' ); unset( $b, $c ); xdebug_debug_zval( 'a' ); //结果 a: (refcount=3, is_ref=0)='new string' a: (refcount=1, is_ref=0)='new string'
<?php $a = array( 'meaning' => '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 )
Ajoutez un élément existant au tableau
<?php $a = array( 'meaning' => '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' )
La suppression d'un élément dans le tableau
est similaire à la suppression d'une variable de la portée
Après la suppression, le "refcount du conteneur où se trouve l'élément dans le tableau" ". La valeur est réduite
<?php $a = array( 'meaning' => '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' )
Lorsqu'on ajoute un tableau lui-même comme élément de ce tableau, les choses deviennent intéressantes
Idem que ci-dessus, appeler unset sur une variable supprimera le symbole et la variable vers laquelle il pointe Le nombre de références dans le conteneur est également réduit de 1
<?php $a = array( 'one' ); $a[] = &$a; xdebug_debug_zval( 'a' ); //结果 a: (refcount=2, is_ref=1)=array ( 0 => (refcount=1, is_ref=0)='one', 1 => (refcount=2, is_ref=1)=... )
Bien qu'il n'y ait plus de symbole dans une portée pointant vers cette structure (c'est-à-dire la variable conteneur), car l'élément de tableau "1" pointe toujours vers le tableau lui-même, ce conteneur ne peut donc pas être effacé.
Comme aucun autre symbole ne le pointe, l'utilisateur n'a aucun moyen d'effacer cette structure, ce qui entraînera une fuite de mémoire.
Heureusement, php effacera cette structure de données à la fin de l'exécution du script, mais avant que php ne l'efface, beaucoup de mémoire sera consommée.
Ce n'est pas grave si la situation ci-dessus ne se produit qu'une ou deux fois, mais si les fuites de mémoire se produisent des milliers, voire des centaines de milliers de fois, c'est évidemment un gros problème
Comme ce que PHP utilisait auparavant Le comptage de références. le mécanisme de mémoire ne peut pas gérer les fuites de mémoire de référence circulaires
L'algorithme de synchronisation est utilisé dans PHP 5.3.0 pour résoudre ce problème de fuite de mémoire
Si un nombre de références augmente, il continuera à être utilisé, et bien sûr il ne le sera plus utilisé. À la poubelle.
Si le nombre de références est réduit à zéro, le conteneur de variables sera effacé (gratuitement)
C'est-à-dire qu'un cycle de déchets ne se produira que lorsque le nombre de références est réduit à une valeur non nulle
Dans une poubelle cycle, en vérifiant la référence Vérifiez si le décompte est décrémenté de 1 et vérifiez quels conteneurs variables ont des temps de référence nuls pour savoir quelle partie est une poubelle
Pour éviter d'avoir à vérifier toutes les références compte, le cycle des déchets peut être réduit
Cet algorithme place toutes les racines possibles (les racines possibles sont des conteneurs de variables zval) dans le tampon racine (marqué en violet, appelé poubelle suspectée), de sorte que chaque racine poubelle possible puisse être assurée en même temps (racine poubelle possible) n'apparaît qu'une seule fois dans le tampon. Le garbage collection est effectué sur tous les différents conteneurs de variables dans le tampon uniquement lorsque le tampon racine est plein. Regardez l'étape A dans l'image ci-dessus.
À l'étape B, simulez la suppression de chaque variable violette. Lors de la simulation de suppression, le nombre de références des variables ordinaires qui ne sont pas violettes peut être réduit de "1". Si le nombre de références d'une variable ordinaire devient 0, simulez à nouveau la suppression de cette variable ordinaire. Chaque variable ne peut être simulée supprimée qu'une seule fois et est marquée en gris après la suppression simulée
À l'étape C, la simulation restaure chaque variable violette. La récupération est conditionnelle. Lorsque le nombre de références de la variable est supérieur à 0, une récupération simulée est effectuée. De même, chaque variable ne peut être restaurée qu'une seule fois. Après restauration, elle est marquée en noir. Il s'agit essentiellement de l'opération inverse de l'étape B. De cette façon, la pile restante de nœuds bleus irrécupérables sont les nœuds bleus qui doivent être supprimés. Parcourez-les à l'étape D et supprimez-les
Il y a deux domaines principaux qui ont un impact sur les performances
Partie. 1 L'un est l'économie d'espace mémoire
L'autre est l'augmentation du temps nécessaire au mécanisme de récupération de place pour libérer la mémoire qui a fui
Le mécanisme de récupération de place en PHP n'est que vrai dans l'algorithme de recyclage du cycle, il y aura une augmentation de la consommation de temps pendant l'exécution. Mais dans les scripts normaux (plus petits), il ne devrait y avoir aucun impact sur les performances.
Cependant, dans le cas de scripts normaux avec des mécanismes de recyclage en cours d'exécution, les économies de mémoire permettront à davantage de scripts de ce type de s'exécuter sur votre serveur en même temps. Parce que la mémoire totale utilisée n'a pas atteint la limite supérieure.
Cet avantage est particulièrement évident dans les scripts de longue durée, tels que les suites de tests de longue durée ou les scripts démons.
(Tutoriel recommandé : Tutoriel vidéo 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!