Descubrí accidentalmente que cuando React se representa en el servidor, cuando Node_env! = Producción, causará fugas de memoria. Problemas específicos: https://github.com/facebook/react/issues/7406. Con el uso generalizado del isomorfismo de nodo y reaccionamiento y otras tecnologías, los problemas como la fuga de memoria del lado del nodo deberían atraer nuestra atención. ¿Por qué el nodo es propenso a las filtraciones de memoria y cómo solucionar problemas después de que ocurre? La siguiente es una breve introducción y ejemplo.
En primer lugar, el nodo se basa en el motor V8, y su método de gestión de memoria es consistente con V8. La siguiente es una breve introducción a los efectos de memoria relevantes de V8.
Límite de memoria V8
El nodo se basa en V8 y puede asignar y administrar objetos JS a través de V8. V8 tiene limitaciones en el uso de la memoria (aproximadamente 1,4 g para la antigua generación del sistema de memoria de memoria de 64 bits, aproximadamente 0,7 g para el sistema de 32 bits, aproximadamente 32 MB para la nueva generación de sistema de 64 bits de memoria y aproximadamente 16 MB para el sistema de 32 bits). Bajo tales restricciones, los objetos de memoria grandes no podrán funcionar. Si este límite se toca accidentalmente, el proceso saldrá.
Causa: V8 bloquea la lógica de la aplicación JavaScript al realizar la recolección de basura, y luego vuelve a ejecutar la lógica de la aplicación JavaScript hasta que termine la recolección de basura. Este comportamiento se llama "parar el mundo". Si la memoria del montón de V8 es de 1,5 GB, V8 tarda más de 50 ms para hacer una pequeña recolección de basura, y se tarda más de 1 segundo en una recolección de basura no incremental.
Establezca la memoria de nueva generación y la memoria de generación anterior para descifrar el límite de memoria predeterminado configurando el nodo-Max-Old-space-size = xxx (Unidad MB) y el nodo --max-new-space-size = xxx (unidad KB).
Composición del montón V8
El montón V8 en realidad no está compuesto por dos partes: la antigua generación y la nueva generación. El montón se puede dividir en varias regiones diferentes:
Tipo de reciclaje de GC
GC incremental
Indica si el recolector de basura recoge (agrega) basura al escanear el espacio de la memoria y borra la basura al final del ciclo de escaneo.
GC no incremental
Cuando se usa un colector de basura no incremental, la basura está vacía tan pronto como se recolecta.
El recolector de basura solo realizará la recolección de basura para el área de memoria de nueva generación, el área de puntero de la antigua generación y el área de datos de la generación anterior. El objeto primero ingresa a la memoria de nueva generación que ocupa menos espacio. La mayoría de los objetos fallarán rápidamente, y el GC no incremental recicla directamente estas pequeñas cantidades de memoria. Si algunos objetos no pueden reciclarse por un período de tiempo, se ingresarán en el área de memoria de la antigua generación. Esta área ejecuta GC incremental poco frecuente y lleva mucho tiempo.
Entonces, ¿cuándo ocurrirá la fuga de memoria?
Rutas de fuga de memoria
La composición de memoria del nodo es principalmente la pieza asignada a través de V8 y la parte asignada por el nodo mismo. La principal limitación de la recolección de basura de V8 es la memoria del montón de V8. Las principales razones de las fugas de memoria: 1. Cache; 2. El consumo de cola no es oportuno; 3. Alcance no lanzado
Análisis de fugas de memoria
Verifique el uso de la memoria V8 (byte de la unidad)
process.MemoryUsage (); {Ress: 47038464, Tdaptotal: 34264656, acumulada: 2052866}Ress: la parte de memoria residente del proceso
Actotal, amenazado: Información de memoria del montón V8
Verifique el uso de la memoria del sistema (byte de la unidad)
os.totalmem()
OS.Freemem ()
Devuelve la memoria total del sistema y la memoria inactiva
Ver registro de recolección de basura
nodo --trace_gc -e "var a = []; for (var i = 0; i <1000000; i ++) {a.push (nueva matriz (100));}" >> gc.log // Registro de recolección de basura
nodo --prof // Registro de rendimiento de ejecución del nodo de salida. Use Windows-Tick.processor para ver.
Herramientas de monitoreo analítico
V8-Profiler captura instantáneas de la memoria del montón V8 y analiza la CPU
El nodo-capitán toma instantáneas de la memoria del montón V8
Uso de la pila de análisis de nodo-mtrace
Node-MemWatch escucha la situación de recolección de basura
Node-memwatch
memwatch.on ('stats', function (info) {console.log (info)}) memwatch.on ('filtración', function (info) {console.log (info)})Evento de estadísticas: cada vez que se realiza una recolección de basura del montón completo, se activará el evento de estadísticas. Este evento pasará estadísticas de memoria.
{"num_full_gc": 17, // cuántas recolecciones de basura de stack stack "num_inc_gc": 8, // cuántas recolecciones de basura incrementales "Heap_Compactions": 8, // cuántas veces la generación anterior se clasifica "estimado_base": 2592568, // la cardinalidad estimada "actual": 2592568, ///////////os Cardenal "," Minalidad ". 2499912, // mínimo "max": 2592568, // máximo "use_trend": 0 // tendencia de usuario}Observe num_full_gc y num_inc_gc reflejar la recolección de basura.
Evento de fuga: si la memoria aún no se libera después de 5 colecciones de basura consecutivas, significa que se producen fugas de memoria. Esta vez se activará un evento de fuga.
{Inicio: viernes, 29 de junio de 2012 14:12:13 GMT, final: viernes, 29 de junio de 2012 14:12:33 GMT, crecimiento: 67984, razón: 'Crecimiento del montón de más de 5 GC consecutivos (20s) - 11.67 MB/HR'}Tonte Diffing Actualidad de memoria de montón Solución de problemas Código de desbordamiento de memoria.
A continuación, usamos un ejemplo para demostrar cómo solucionar problemas de filtraciones de memoria:
Primero creamos un ejemplo que causa fugas de memoria:
//app.jsvar app = request ('express') (); var http = require ('http'). Server (app); var heteapDump = require ('hedisdump'); var fleatObjs = []; function fleatClass () {this.x = 1;} app.get ('/', function (req, res) {console.log (log ('get/'); <1000; function () {console.log ('escuchar en el puerto 3000');});Aquí simulamos fugas de memoria configurando una matriz que aumenta constantemente y no se recupera.
Use el módulo Heap-Dump para registrar las instantáneas de memoria regularmente e importe instantáneas a través de los perfiles de herramientas de desarrollador de Chrome para comparación y análisis.
Podemos ver que después de que el navegador accede a localhost: 3000 y lo actualiza muchas veces, el tamaño de la instantánea ha estado creciendo, e incluso si no se solicita, no disminuye, lo que indica que ha ocurrido una fuga.
Luego importamos instantáneas a través de los perfiles de herramientas de desarrollador de Chrome. Al configurar la comparación, compare la instantánea inicial, envíe solicitudes y luego envíe solicitudes para enviar instantáneas de memoria en estas tres etapas. Puede encontrar que LeakClass ha aumentado en lo nuevo de la derecha. Siempre positivo en Delta, significa que no ha sido reciclado.
resumen
Para las fugas de memoria, puede usar MemWatch para implantar o informar el proceso de memoria MemoryUsage para monitorear regularmente y establecer un umbral de alarma para el monitoreo.
Cuando se encuentran fugas de memoria, si se permiten, puede ejecutar Node-Heapdump localmente y usar instantáneas de memoria cronometradas para generar. Y use la instantánea para analizar la causa de la fuga a través de los perfiles de Chrome. Si no es posible la depuración local, use V8-Profiler para emitir instantáneas de memoria en el servidor de prueba para comparar y analizar JSON (se requiere la intrusión del código).
En qué circunstancias se deben considerar, MemWatch/Heapdump está habilitado. Considere la frecuencia del montón para evitar quedarse sin CPU. También se pueden considerar otras formas de detectar el crecimiento de la memoria, como el proceso de monitoreo directamente. MemoryUsage ().
Tenga cuidado con el juicio erróneo, los picos de uso de memoria a corto plazo se comportan como fugas de memoria. Si su aplicación de repente consume mucha CPU y memoria, el tiempo de procesamiento puede abarcar varios ciclos de recolección de basura, y luego MemWatch puede juzgarlo mal como una fuga de memoria. Sin embargo, en este caso, una vez que su aplicación use estos recursos, el consumo de memoria volverá a los niveles normales. Por lo tanto, es importante tener en cuenta que las filtraciones de memoria se informan continuamente, y una o dos alarmas repentinas se pueden ignorar.