Aprende a usar Chrome y DevTools para encontrar problemas de memoria que afectan el rendimiento de la página, como fugas de memoria, aumento excesivo de la memoria y recolecciones de elementos no utilizados frecuentes.
Resumen
- Descubre cuánta memoria usa tu página con el Administrador de tareas de Chrome.
- Visualiza el uso de la memoria a lo largo del tiempo con las grabaciones de Cronograma.
- Identifica los árboles del DOM desconectados (una causa común de fugas de memoria) con Heap Snapshots.
- Descubre cuándo se asigna memoria nueva en tu montón de JS con las grabaciones del cronograma de asignación.
- Identifica los elementos desconectados que retiene la referencia de JavaScript.
Descripción general
En el espíritu del modelo de rendimiento RAIL, el enfoque de tus esfuerzos de rendimiento debe ser los usuarios.
Los problemas de memoria son importantes porque los usuarios suelen percibirlos. Los usuarios pueden percibir problemas de memoria de las siguientes maneras:
- El rendimiento de una página empeora progresivamente con el tiempo. Es posible que esto sea un síntoma de una fuga de memoria. Una fuga de memoria ocurre cuando un error en la página hace que esta use cada vez más memoria con el tiempo.
- El rendimiento de una página es deficiente de forma constante. Es posible que esto sea un síntoma de aumento excesivo de la memoria. El aumento excesivo de la memoria ocurre cuando una página usa más memoria de la necesaria para obtener una velocidad óptima.
- El rendimiento de una página se retrasa o parece detenerse con frecuencia. Es posible que esto sea un síntoma de reconstrucciones de elementos no usados frecuentes. La recolección de elementos no utilizados ocurre cuando el navegador recupera la memoria. El navegador decide cuándo sucede esto. Durante las colecciones, se detiene toda la ejecución de secuencias de comandos. Por lo tanto, si el navegador realiza muchas limpiezas de basura, la ejecución de la secuencia de comandos se detendrá mucho.
Aumento excesivo de la memoria: ¿cuándo es “demasiado”?
Una fuga de memoria es fácil de definir. Si un sitio usa cada vez más memoria, entonces hay una fuga. Sin embargo, el aumento excesivo de la memoria es un poco más difícil de identificar. ¿Qué se considera “usar demasiada memoria”?
No hay cifras exactas, ya que los diferentes dispositivos y navegadores tienen capacidades diferentes. La misma página que se ejecuta sin problemas en un smartphone de alta gama puede fallar en uno de gama baja.
La clave aquí es usar el modelo RAIL y enfocarte en tus usuarios. Descubre qué dispositivos son populares entre tus usuarios y, luego, prueba tu página en esos dispositivos. Si la experiencia es siempre deficiente, es posible que la página supere las capacidades de memoria de esos dispositivos.
Supervisa el uso de memoria en tiempo real con el Administrador de tareas de Chrome
Usa el Administrador de tareas de Chrome como punto de partida para investigar el problema de memoria. El Administrador de tareas es un monitor en tiempo real que te indica cuánta memoria usa una página.
Presiona Mayúsculas + Esc o ve al menú principal de Chrome y selecciona Más herramientas > Administrador de tareas para abrirlo.
Haz clic con el botón derecho en el encabezado de la tabla del Administrador de tareas y habilita la memoria de JavaScript.
Estas dos columnas te indican diferentes aspectos sobre cómo tu página usa la memoria:
- La columna Uso de memoria representa la memoria del SO. Los nodos DOM se almacenan en la memoria del SO. Si este valor aumenta, se crean nodos DOM.
La columna Memoria de JavaScript representa el montón de JS. Esta columna contiene dos valores. El valor que te interesa es el número en vivo (el número entre paréntesis). El número en vivo representa la cantidad de memoria que usan los objetos accesibles de tu página. Si este número aumenta, significa que se están creando objetos nuevos o que los objetos existentes están creciendo.
Visualiza las fugas de memoria con las grabaciones de rendimiento
También puedes usar el panel Rendimiento como otro punto de partida en tu investigación. El panel Rendimiento te ayuda a visualizar el uso de memoria de una página a lo largo del tiempo.
- Abre el panel Rendimiento en DevTools.
- Habilita la casilla de verificación Memory.
- Realiza una grabación.
Para demostrar las grabaciones de memoria de rendimiento, considera el siguiente código:
var x = [];
function grow() {
for (var i = 0; i < 10000; i++) {
document.body.appendChild(document.createElement('div'));
}
x.push(new Array(1000000).join('x'));
}
document.getElementById('grow').addEventListener('click', grow);
Cada vez que se presiona el botón al que se hace referencia en el código, se agregan diez mil nodos div
al cuerpo del documento y se envía una cadena de un millón de caracteres x
al array x
.
Cuando se ejecuta este código, se produce una grabación de Rutas como la que se muestra en la siguiente captura de pantalla:
En primer lugar, una explicación de la interfaz de usuario. El gráfico HEAP en el panel Overview (debajo de NET) representa el montón de JS. Debajo del panel Resumen, se encuentra el panel Contador. Aquí puedes ver el uso de memoria desglosado por montón de JS (igual que el gráfico HEAP en el panel Overview), documentos, nodos DOM, objetos de escucha y memoria de GPU. Si inhabilitas una casilla de verificación, esta se ocultará del gráfico.
Ahora, un análisis del código en comparación con la captura de pantalla. Si observas el contador de nodos (el gráfico verde), verás que coincide perfectamente con el código. El recuento de nodos aumenta en pasos discretos. Puedes suponer que cada aumento en el recuento de nodos es una llamada a grow()
. El gráfico del montón de JS (el gráfico azul) no es tan sencillo. De acuerdo con las prácticas recomendadas, la primera disminución es, en realidad, una recolección de elementos no utilizados forzada (se logra presionando el botón Collect garbage). A medida que avanza la grabación, puedes ver que el tamaño del montón de JS aumenta. Esto es natural y esperado: el código JavaScript crea los nodos DOM en cada clic del botón y realiza mucho trabajo cuando crea la cadena de un millón de caracteres. Lo más importante aquí es el hecho de que el montón de JS termina más alto de lo que comenzó (el “inicio” aquí es el punto después de la recolección de basura forzada). En el mundo real, si vieras este patrón de aumento del tamaño del montón de JS o del tamaño del nodo, podría significar una fuga de memoria.
Descubre las fugas de memoria del árbol del DOM desconectado con las instantáneas del montón
Un nodo DOM solo se puede recolectar con elementos no utilizados cuando no hay referencias a él desde el árbol DOM de la página o el código JavaScript. Se dice que un nodo está "desconectado" cuando se quita del árbol del DOM, pero algunos JavaScript aún hacen referencia a él. Los nodos DOM separados son una causa común de fugas de memoria. En esta sección, aprenderás a usar los generadores de perfiles de montón de DevTools para identificar nodos separados.
Este es un ejemplo simple de nodos DOM separados.
var detachedTree;
function create() {
var ul = document.createElement('ul');
for (var i = 0; i < 10; i++) {
var li = document.createElement('li');
ul.appendChild(li);
}
detachedTree = ul;
}
document.getElementById('create').addEventListener('click', create);
Si haces clic en el botón al que se hace referencia en el código, se creará un nodo ul
con diez elementos secundarios li
. El código hace referencia a estos nodos, pero no existen en el árbol del DOM, por lo que están separados.
Las instantáneas de montón son una forma de identificar los nodos desconectados. Como su nombre lo indica, las instantáneas del montón te muestran cómo se distribuye la memoria entre los objetos JS y los nodos DOM de tu página en el momento de la instantánea.
Para crear una instantánea, abre DevTools y ve al panel Memory, selecciona el botón de selección Heap Snapshot y, luego, presiona el botón Take snapshot.
Es posible que la instantánea tarde un poco en procesarse y cargarse. Cuando termine, selecciónalo en el panel izquierdo (llamado Heap snapshots).
Escribe Detached
en el cuadro de entrada Filtro de clase para buscar árboles de DOM separados.
Expande los corchetes para investigar un árbol desconectado.
Haz clic en un nodo para investigarlo más a fondo. En el panel Objetos, puedes ver más información sobre el código que hace referencia a él. Por ejemplo, en la siguiente captura de pantalla, puedes ver que la variable detachedTree
hace referencia al nodo. Para corregir esta filtración de memoria en particular, debes estudiar el código que usa detachedTree
y asegurarte de que quite su referencia al nodo cuando ya no sea necesaria.
Identifica fugas de memoria del montón de JS con los cronogramas de asignación
El Cronograma de asignación es otra herramienta que puede ayudarte a rastrear las fugas de memoria en tu montón de JS.
Para demostrar el Cronograma de asignación, considera el siguiente código:
var x = [];
function grow() {
x.push(new Array(1000000).join('x'));
}
document.getElementById('grow').addEventListener('click', grow);
Cada vez que se presiona el botón al que se hace referencia en el código, se agrega una cadena de un millón de caracteres al array x
.
Para grabar un Cronograma de asignaciones, abre DevTools, ve al panel Memoria, selecciona el botón de selección Asignaciones en el cronograma, presiona el botón
Grabar, realiza la acción que sospechas que está causando la fuga de memoria y, luego, presiona el botón Detener la grabación cuando termines.Mientras grabas, observa si aparecen barras azules en el Cronograma de asignación, como en la siguiente captura de pantalla.
Esas barras azules representan nuevas asignaciones de memoria. Esas nuevas asignaciones de memoria son tus candidatos para las fugas de memoria. Puedes acercar una barra para filtrar el panel Constructor y mostrar solo los objetos que se asignaron durante el período especificado.
Expande el objeto y haz clic en su valor para ver más detalles en el panel Objeto. Por ejemplo, en la siguiente captura de pantalla, si ves los detalles del objeto que se asignó recientemente, podrás ver que se asignó a la variable x
en el alcance Window
.
Investiga la asignación de memoria por función
Usa el tipo de perfil Muestra de asignación en el panel Memoria para ver la asignación de memoria por función de JavaScript.
- Selecciona el botón de selección Muestreo de asignación. Si hay un trabajador en la página, puedes seleccionarlo como el objetivo de generación de perfiles en la ventana Select JavaScript VM instance.
- Presiona el botón Start.
- Realiza las acciones en la página que deseas investigar.
- Presiona el botón Stop cuando hayas terminado todas tus acciones.
DevTools muestra un desglose de la asignación de memoria por función. La vista predeterminada es Heavy (Bottom Up), que muestra las funciones que asignaron la mayor cantidad de memoria en la parte superior.
Identifica los objetos que retiene la referencia de JS
El perfil Elementos desconectados muestra los elementos desconectados que persisten porque el código JavaScript hace referencia a ellos.
Registra un perfil de elementos separados para ver los nodos y la cantidad de nodos HTML exactos.
Detecta recolecciones de elementos no utilizados frecuentes
Si tu página parece detenerse con frecuencia, es posible que tengas problemas de recolección de elementos no utilizados.
Puedes usar el Administrador de tareas de Chrome o las grabaciones de memoria de Rutas para detectar colecciones de basura frecuentes. En el Administrador de tareas, los valores de Memoria o Memoria de JavaScript que aumentan y disminuyen con frecuencia representan reconstrucciones de elementos no usados frecuentes. En las grabaciones de la cronología, los gráficos de recuento de nodos o montón de JS que suben y bajan con frecuencia indican limpiezas de basura frecuentes.
Una vez que hayas identificado el problema, puedes usar una grabación de Allocation Timeline para averiguar dónde se asigna la memoria y qué funciones causan las asignaciones.