J'ai découvert accidentellement que lorsque React est rendu dans le serveur, lorsque Node_env! = Production, cela provoquera des fuites de mémoire. Problèmes spécifiques: https://github.com/facebook/react/issues/7406. Avec l'utilisation généralisée de l'isomorphisme de nœud et de réaction et d'autres technologies, des problèmes tels que la fuite de mémoire côté nœud devraient attirer notre attention. Pourquoi le nœud est-il sujet aux fuites de mémoire et comment dépanner une fois qu'il se produit? Ce qui suit est une brève introduction et un exemple.
Tout d'abord, le nœud est basé sur le moteur V8, et sa méthode de gestion de la mémoire est cohérente avec V8. Ce qui suit est une brève introduction aux effets de mémoire pertinents du V8.
Limite de mémoire V8
Le nœud est construit sur V8 et peut allouer et gérer les objets JS via V8. V8 a des limites à l'utilisation de la mémoire (environ 1,4 g pour l'ancienne génération de système de mémoire 64 bits, environ 0,7 g pour le système 32 bits, environ 32 Mo pour la nouvelle génération de système de mémoire 64 bits et environ 16 Mo pour le système 32 bits). Selon de telles restrictions, les grands objets de mémoire ne seront pas en mesure de fonctionner. Si cette frontière est accidentellement touchée, le processus sortira.
Cause: V8 bloque la logique de l'application JavaScript lors de l'exécution de la collection des ordures, puis réexécute la logique de l'application JavaScript jusqu'à la fin de la collection des ordures. Ce comportement est appelé "stop-the-monde". Si la mémoire du tas de V8 est de 1,5 Go, il faut plus de 50 ms pour que le V8 fasse une petite collection de déchets, et il faut plus d'une seconde pour une collection d'ordures non incrimenturelle.
Définissez la mémoire de la nouvelle génération et l'ancienne mémoire de génération pour casser la limite de mémoire par défaut en définissant le nœud --max-old-space-size = xxx (unité MB) et le nœud --max-new-space-size = xxx (unité kb).
Composition de tas de V8
Le tas V8 n'est pas réellement composé de deux parties: l'ancienne génération et la nouvelle génération. Le tas peut être divisé en plusieurs régions différentes:
Type de recyclage GC
GC incrémentiel
Indique si le collecteur des ordures recueille (ajoute) les ordures lors de la numérisation de l'espace mémoire et efface les ordures à la fin du cycle de balayage.
GC non incrémental
Lors de l'utilisation d'un collecteur de déchets non incrimental, les ordures sont vides dès qu'elle est collectée.
Le collecteur des ordures ne fera que la collecte des ordures pour la zone de mémoire de la nouvelle génération, la zone du pointeur à l'ancienne et la zone de données de l'ancienne génération. L'objet entre d'abord dans la mémoire de la nouvelle génération qui prend moins de place. La plupart des objets échoueront rapidement et le GC non incrémental recycle directement ces petites quantités de mémoire. Si certains objets ne peuvent pas être recyclés pendant un certain temps, ils seront entrés dans la zone de mémoire de l'ancienne génération. Cette zone exécute un GC incrémentiel peu fréquente et prend beaucoup de temps.
Alors, quand la fuite de mémoire se produira-t-elle?
Chemins de fuite de mémoire
La composition de la mémoire du nœud est principalement la pièce allouée via V8 et la pièce allouée par le nœud lui-même. La principale limitation de la collection de déchets de V8 est la mémoire du tas de V8. Les principales raisons des fuites de mémoire: 1. Cache; 2. La consommation de file d'attente n'est pas opportune; 3. Portée non libérée
Analyse des fuites de mémoire
Vérifiez l'utilisation de la mémoire V8 (octet d'unité)
process.MemoryUsage (); {Ress: 47038464, Heaptotal: 34264656, Heapused: 2052866}Ress: la partie de la mémoire résidente du processus
heaptotal, taspus: V8 tas de mémoire information de mémoire
Vérifiez l'utilisation de la mémoire du système (octet d'unité)
os.totalmem()
os.freemem ()
Renvoie la mémoire système totale et la mémoire inactive
Voir le journal de collecte des ordures
node --trace_gc -e "var a = []; for (var i = 0; i <1000000; i ++) {a.push (nouveau tableau (100));}" >> gc.log //
Node --prof // Output Node Exécution Performance Journal. Utilisez Windows-Tick.processor pour afficher.
Outils de surveillance analytique
V8-Profiler capture des instantanés de la mémoire du tas V8 et analyse le processeur
Node-Hapdump saisit des instantanés de la mémoire du tas de V8
Utilisation de la pile d'analyse de nœud-mtrace
Node-memwatch écoute la situation de la collecte des ordures
Node-memwatch
memwatch.on ('statts', fonction (info) {console.log (info)}) memwatch.on ('leak', fonction (info) {console.log (info)})Événement de statistiques: Chaque fois qu'une collection de déchets complète est effectuée, l'événement Statts sera déclenché. Cet événement passera des statistiques de mémoire.
{"num_full_gc": 17, //How many full-stack garbage collection "num_inc_gc": 8, //How many incremental garbage collection "heap_compactions": 8, //How many times the old generation are sorted out "estimated_base": 2592568, //The estimated cardinality "current_base": 2592568, //The current cardinality "min": 2499912, // minimum "max": 2592568, // maximum "usage_trend": 0 // tendance utilisateur}Observez NUM_FULL_GC et NUM_INC_GC Réfléchissez à la collecte des ordures.
Événement de fuite: si la mémoire n'est toujours pas libérée après 5 collections de déchets consécutives, cela signifie que des fuites de mémoire se produisent. Cette fois, un événement de fuite sera déclenché.
{Start: ven, 29 juin 2012 14:12:13 GMT, fin: ven, 29 juin 2012 14:12:33 GMT, Growth: 67984, raison: 'Croissance du tas sur 5 GC consécutifs (20S) - 11,67 MB / HR'}Tas de comparaison de la mémoire de mémoire de tas de tas du code de débordement de la mémoire.
Ci-dessous, nous utilisons un exemple pour démontrer comment dépanner les fuites de mémoire:
Nous créons d'abord un exemple qui provoque des fuites de mémoire:
//app.jsvar app = require ('express') (); var http = required ('http'). server (app); var heapdump = require ('heapdump'); var leakobjs = []; function leakclass () {this.x = 1;} app.get ('/', fonction (req, res) {console.log ('); 0; 3000); http.Listen (3000, function () {console.log ('écoute sur le port 3000');});Ici, nous simulons les fuites de mémoire en configurant un tableau qui augmente constamment et ne se récupère pas.
Utilisez le module tas-dump pour enregistrer régulièrement des instantanés de mémoire et importez des instantanés via les profils d'outils de développeur Chrome pour la comparaison et l'analyse.
Nous pouvons voir qu'après que le navigateur accède au localhost: 3000 et le rafraîchit plusieurs fois, la taille de l'instantané a augmenté, et même si elle n'est pas demandée, elle ne diminue pas, indiquant qu'une fuite s'est produite.
Ensuite, nous importons des instantanés via les profils d'outils de développeur Chrome. En définissant la comparaison, comparez l'instantané initial, envoyez des demandes, puis envoyez des demandes pour envoyer des instantanés de mémoire dans ces trois étapes. Vous pouvez constater que la couverture a augmenté dans le nouveau sur la droite. Toujours positif dans Delta, cela signifie qu'il n'a pas été recyclé.
résumé
Pour les fuites de mémoire, vous pouvez utiliser memwatch pour implanter, ou signaler l'utilisation de la mémoire de processus.
Lorsque des fuites de mémoire sont trouvées, si elles sont autorisées, vous pouvez exécuter Node-HapDump localement et utiliser des instantanés de mémoire chronométrés à générer. Et utiliser l'instantané pour analyser la cause de la fuite à travers les profils chromés. Si le débogage local n'est pas possible, utilisez V8-Profiler pour sortir des instantanés de mémoire sur le serveur de test pour comparer et analyser JSON (l'intrusion de code est requise).
Dans quelles circonstances doivent être prises en compte, Memwatch / Heapdump est activée. Considérez la fréquence de tas pour éviter de manquer de CPU. D'autres moyens de détecter la croissance de la mémoire peuvent également être pris en compte, comme le processus de surveillance directe.MemoryUsage ().
Méfiez-vous des erreurs de jugement, les pics d'utilisation de la mémoire à court terme se comportent comme des fuites de mémoire. Si votre application consomme soudainement beaucoup de processeur et de mémoire, le temps de traitement peut s'étendre sur plusieurs cycles de collecte des ordures, puis Memwatch peut le mal juger en tant que fuite de mémoire. Cependant, dans ce cas, une fois que votre application utilise ces ressources, la consommation de mémoire reviendra à des niveaux normaux. Il est donc important de noter que les fuites de mémoire sont rapportées en continu et une ou deux alarmes soudaines peuvent être ignorées.