À propos des fuites de mémoire
Webman est un framework en mémoire résidente, donc nous devons prêter un peu d'attention aux fuites de mémoire. Cependant, les développeurs ne doivent pas s'inquiéter outre mesure, car les fuites de mémoire se produisent dans des conditions très extrêmes et sont facilement évitables. L'expérience de développement avec Webman est essentiellement similaire à celle des frameworks traditionnels, il n'est pas nécessaire de faire des opérations superflues pour la gestion de la mémoire.
Remarque
Le processus de monitor intégré à Webman surveillera l'utilisation de la mémoire de tous les processus. Si l'utilisation de la mémoire d'un processus est sur le point d'atteindre la valeur fixée parmemory_limit
dans php.ini, il redémarrera automatiquement et en toute sécurité le processus concerné pour libérer de la mémoire, sans impact sur les activités commerciales.
Définition d'une fuite de mémoire
À mesure que le nombre de requêtes augmente, la mémoire utilisée par Webman augmente également de manière illimitée (notez qu'il s'agit d'une augmentation illimitée), atteignant plusieurs centaines de Mo, voire plus ; c'est ce qui constitue une fuite de mémoire. Si la mémoire augmente, mais ne continue pas à croître par la suite, cela ne compte pas comme une fuite de mémoire.
Une utilisation de plusieurs dizaines de Mo par processus est tout à fait normale. Lorsque le processus traite des requêtes très volumineuses ou maintient un grand nombre de connexions, l'utilisation de mémoire d'un seul processus peut atteindre plusieurs centaines de Mo. Après usage, PHP peut ne pas rendre toute cette mémoire au système d'exploitation. Au lieu de cela, il la conserve pour une réutilisation ultérieure, il est donc normal de constater que l'occupation de la mémoire augmente après le traitement d'une grande requête, sans que la mémoire ne soit libérée (l'appel de la méthode gc_mem_caches()
peut libérer une partie de la mémoire inutilisée).
Comment se produisent les fuites de mémoire
Les fuites de mémoire se produisent si et seulement si les deux conditions suivantes sont remplies :
- Il existe un tableau à longue durée de vie (notez qu'il s'agit d'un tableau à longue durée de vie, les tableaux ordinaires ne posent pas de problème).
- Et ce tableau à longue durée de vie s'étend indéfiniment (les données sont insérées dans celui-ci sans jamais être nettoyées).
Si les conditions 1 et 2 sont toutes deux satisfaites (notez qu'elles doivent être toutes les deux satisfaites), alors une fuite de mémoire se produira. Inversement, ne pas respecter ces conditions ou n'en respecter qu'une seule ne constitue pas une fuite de mémoire.
Tableaux à longue durée de vie
Les tableaux à longue durée de vie dans Webman comprennent :
- Les tableaux définis avec le mot clé
static
. - Les propriétés de tableau d'un singleton.
- Les tableaux définis avec le mot clé
global
.
Attention
Webman autorise l'utilisation de données à longue durée de vie, mais il est nécessaire de s'assurer que les données contenues dans ces tableaux sont limitées, et que le nombre d'éléments ne s'étendra pas indéfiniment.
Voici quelques exemples pour illustrer.
Tableau static
en expansion infinie
class Foo
{
public static $data = [];
public function index(Request $request)
{
self::$data[] = time();
return response('hello');
}
}
Le tableau $data
défini avec le mot clé static
est un tableau à longue durée de vie, et dans cet exemple, le tableau $data
s'expand à chaque requête, entraînant une fuite de mémoire.
Propriété de tableau de singleton en expansion infinie
class Cache
{
protected static $instance;
public $data = [];
public function instance()
{
if (!self::$instance) {
self::$instance = new self;
}
return self::$instance;
}
public function set($key, $value)
{
$this->data[$key] = $value;
}
}
Code d'appel
class Foo
{
public function index(Request $request)
{
Cache::instance()->set(time(), time());
return response('hello');
}
}
Cache::instance()
retourne une instance unique de Cache, qui est une instance de classe à longue durée de vie. Bien que sa propriété $data
ne soit pas définie avec le mot clé static
, la classe elle-même étant à longue durée de vie, $data
est également un tableau à longue durée de vie. À mesure que différents clés sont ajoutées au tableau $data
, la mémoire utilisée par le programme augmente également, entraînant une fuite de mémoire.
Attention
Si les clés ajoutées parCache::instance()->set(key, value)
sont d'un nombre limité, alors il n'y aura pas de fuite de mémoire, car le tableau$data
ne s'étend pas indéfiniment.
Tableau global
en expansion infinie
class Index
{
public function index(Request $request)
{
global $data;
$data[] = time();
return response($foo->sayHello());
}
}
Un tableau défini avec le mot clé global
ne sera pas récupéré après l'exécution de la fonction ou de la méthode de classe, il constitue donc un tableau à longue durée de vie. Le code ci-dessus, à mesure que le nombre de requêtes augmente, entraînera une fuite de mémoire. De même, un tableau défini avec le mot clé static
dans une fonction ou une méthode sera également un tableau à longue durée de vie, et s'il s'étend indéfiniment, une fuite de mémoire se produira également, par exemple :
class Index
{
public function index(Request $request)
{
static $data = [];
$data[] = time();
return response($foo->sayHello());
}
}
Recommandations
Il est conseillé aux développeurs de ne pas s'inquiéter particulièrement des fuites de mémoire, car elles se produisent très rarement. Si, par malheur, cela se produit, nous pouvons identifier le segment de code qui cause la fuite grâce aux tests de pression, permettant ainsi de localiser le problème. Même si le développeur ne trouve pas le point de fuite, le service monitor intégré à Webman redémarrera automatiquement et en toute sécurité les processus concernés pour libérer de la mémoire.
Si vous souhaitez vraiment essayer de minimiser les fuites de mémoire, vous pouvez suivre ces recommandations :
- Évitez autant que possible les tableaux définis avec les mots clés
global
etstatic
, et s'ils sont utilisés, assurez-vous qu'ils ne s'étendent pas indéfiniment. - Pour les classes que vous ne connaissez pas bien, essayez d'éviter d'utiliser des singletons ; utilisez plutôt le mot clé
new
pour les initialiser. Si un singleton est nécessaire, vérifiez s'il a des propriétés de tableau en expansion infinie.