Arreglar problemas de memoria

Aprenda a utilizar Chrome y DevTools para encontrar problemas de memoria que afecten al rendimiento de la página, incluidas las fugas de memoria, la sobrecarga de memoria y las recolecciones de basura frecuentes.

Resumen #

  • Averigüe cuánta memoria está utilizando actualmente su página con el Administrador de tareas de Chrome.
  • Visualice el uso de la memoria a lo largo del tiempo con las grabaciones de la línea de tiempo.
  • Identifique los árboles DOM desprendidos (una causa común de las fugas de memoria) con las instantáneas de la pila.
  • Averigüe cuándo se está asignando nueva memoria en su pila JS con las grabaciones de la línea de tiempo de asignación.

Resumen #

En el espíritu del modelo de rendimiento RAIL, el foco de sus esfuerzos de rendimiento debe ser sus usuarios.

Los problemas de memoria son importantes porque a menudo son perceptibles por los usuarios. Los usuarios pueden percibir los problemas de memoria de las siguientes maneras:

  • El rendimiento de una página empeora progresivamente con el tiempo. Esto es posiblemente un síntoma de una fuga de memoria. Una fuga de memoria es cuando un error en la página hace que ésta utilice progresivamente más y más memoria con el tiempo.
  • El rendimiento de una página es constantemente malo. Esto es posiblemente un síntoma de hinchazón de memoria. La sobrecarga de memoria se produce cuando una página utiliza más memoria de la necesaria para una velocidad óptima de la página.
  • El rendimiento de una página se retrasa o parece detenerse con frecuencia. Esto es posiblemente un síntoma de colecciones de basura frecuentes. La recolección de basura es cuando el navegador recupera la memoria. El navegador decide cuándo ocurre esto. Durante la recolección, toda la ejecución del script se detiene. Así que si el navegador está recolectando basura mucho, la ejecución de scripts se va a pausar mucho.
    • Inflación de la memoria: ¿cuánto es «demasiado»?

      Una fuga de memoria es fácil de definir. Si un sitio está usando progresivamente más y más memoria, entonces usted tiene una fuga. Pero la hinchazón de memoria es un poco más difícil de precisar. ¿Qué es lo que se considera «usar demasiada memoria»?

      Aquí no hay números concretos, porque los distintos dispositivos y navegadores tienen capacidades diferentes. La misma página que se ejecuta sin problemas en un smartphone de gama alta podría bloquearse en un smartphone de gama baja.

      La clave aquí es utilizar el modelo RAIL y centrarse en sus usuarios. Averigua qué dispositivos son populares entre tus usuarios y luego prueba tu página en esos dispositivos. Si la experiencia es consistentemente mala, la página puede estar excediendo las capacidades de memoria de esos dispositivos.

      Monitorear el uso de la memoria en tiempo real con el Administrador de Tareas de Chrome #

      Utilice el Administrador de Tareas de Chrome como punto de partida para su investigación de problemas de memoria. El Administrador de tareas es un monitor en tiempo real que le indica cuánta memoria está utilizando una página en ese momento.

  1. Pulse Shift+Esc o vaya al menú principal de Chrome y seleccione Más herramientas > Administrador de tareas para abrir el Administrador de tareas.

    Abrir el Administrador de tareas

  2. Haz clic con el botón derecho en la cabecera de la tabla del Administrador de tareas y habilita la memoria JavaScript.

    Habilitando la memoria JS

  3. Estas dos columnas te dicen cosas diferentes sobre cómo tu página está usando la memoria:

  • La columna Memoria representa la memoria nativa. Los nodos DOM se almacenan en la memoria nativa. Si este valor está aumentando, los nodos DOM se están creando.
  • La columna Memoria JavaScript representa el montón de JS. Esta columna contiene dos valores. El valor que te interesa es el número vivo (el número entre paréntesis). El número vivo representa la cantidad de memoria que los objetos accesibles en su página están utilizando. Si este número está aumentando, o bien se están creando nuevos objetos, o los objetos existentes están creciendo.

Visualice las fugas de memoria con las grabaciones de la Línea de tiempo #

También puede utilizar el panel Línea de tiempo como otro punto de partida en su investigación. El panel Línea de tiempo le ayuda a visualizar el uso de la memoria de una página a lo largo del tiempo.

  1. Abra el panel Línea de tiempo en DevTools.
  2. Active la casilla de verificación Memoria.
  3. Haga una grabación.
    1. Consejo: Es una buena práctica comenzar y terminar su grabación con una recolección de basura forzada. Haga clic en el botón de recolección de basura (botón de recolección de basura forzada) mientras graba para forzar la recolección de basura.

      Para demostrar las grabaciones de memoria de Timeline, considere el código siguiente:

      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 pulsa el botón al que se hace referencia en el código, se añaden diez mil nodos div al cuerpo del documento, y una cadena de un millón de caracteres x se introduce en la matriz x. La ejecución de este código produce una grabación de la línea de tiempo como la siguiente captura de pantalla:

      ejemplo de crecimiento simple

      Primero, 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 de visión general está el panel de contadores. Aquí puede ver el uso de la memoria desglosado por el montón de JS (igual que el gráfico HEAP en el panel de visión general), los documentos, los nodos DOM, los oyentes y la memoria de la GPU. Desactivar una casilla la oculta del gráfico.

      Ahora, un análisis del código comparado con la captura de pantalla. Si se observa el contador de nodos (el gráfico verde) se puede ver que coincide limpiamente con el código. El contador de nodos aumenta en pasos discretos. Puedes suponer que cada incremento en el conteo de nodos es una llamada a grow(). El gráfico del montón de JS (el gráfico azul) no es tan sencillo. Siguiendo las mejores prácticas, la primera caída es en realidad una recolección de basura forzada (lograda al presionar el botón de recolección de basura). A medida que avanza la grabación, se puede ver que el tamaño de la pila de JS aumenta. Esto es natural y esperado: el código JavaScript está creando los nodos del DOM en cada clic de botón y haciendo mucho trabajo cuando crea la cadena de un millón de caracteres. La clave aquí es el hecho de que el montón de JS termina más alto de lo que comenzó (el «comienzo» 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 heap JS o del tamaño del nodo, significaría potencialmente una fuga de memoria.

      Descubre las fugas de memoria del árbol DOM desvinculado con Heap Snapshots #

      Un nodo DOM sólo puede ser recogido de la basura cuando no hay referencias a él ni desde el árbol DOM de la página ni desde el código JavaScript. Se dice que un nodo está «desprendido» cuando se elimina del árbol DOM pero algún JavaScript sigue haciendo referencia a él. Los nodos DOM desvinculados son una causa común de fugas de memoria. Esta sección le enseña a utilizar los perfiladores de heap de DevTools para identificar los nodos desprendidos.

      Aquí tiene un ejemplo sencillo de nodos DOM desprendidos.

      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);

      Al hacer clic en el botón referenciado en el código se crea un nodo ul con diez li hijos. Estos nodos son referenciados por el código pero no existen en el árbol del DOM, por lo que están separados.

      Las instantáneas de heap son una forma de identificar los nodos separados. Como su nombre indica, las instantáneas de heap 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 Perfiles, selecciona el botón de opción Tomar instantánea de montón y, a continuación, pulsa el botón Tomar instantánea.

      tomar instantánea de montón

      La instantánea puede tardar un tiempo en procesarse y cargarse. Una vez que haya terminado, selecciónela en el panel de la izquierda (llamado HEAP SNAPSHOTS).

      Escriba Detached en el cuadro de texto del filtro de clase para buscar árboles DOM desprendidos.

      filtro de nodos desprendidos

      Expanda los quilates para investigar un árbol desprendido.

      investigar árbol desprendido

      Los nodos resaltados en amarillo tienen referencias directas a ellos desde el código JavaScript. Los nodos resaltados en rojo no tienen referencias directas. Sólo están vivos porque forman parte del árbol del nodo amarillo. En general, usted quiere centrarse en los nodos amarillos. Arregla tu código para que el nodo amarillo no esté vivo durante más tiempo del necesario, y también te deshaces de los nodos rojos que forman parte del árbol del nodo amarillo.

      Haz clic en un nodo amarillo para investigarlo más a fondo. En el panel Objetos puedes ver más información sobre el código que lo está referenciando. Por ejemplo, en la captura de pantalla de abajo puedes ver que la variable detachedTree está haciendo referencia al nodo. Para arreglar esta fuga de memoria en particular, deberías estudiar el código que utiliza detachedTree y asegurarte de que elimina su referencia al nodo cuando ya no es necesario.

      investigando un nodo amarillo

      Identificar las fugas de memoria del heap JS con Allocation Timelines #

      El Allocation Timeline es otra herramienta que puede ayudarte a rastrear las fugas de memoria en tu heap JS.

      Para demostrar la Línea de Tiempo de Asignación considere 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 pulsa el botón referenciado en el código, se añade una cadena de un millón de caracteres a la matriz x.

      Para grabar una línea de tiempo de asignación, abra DevTools, vaya al panel Perfiles, seleccione el botón de opción Grabar línea de tiempo de asignación, pulse el botón Iniciar, realice la acción que sospecha que está causando la fuga de memoria y, a continuación, pulse el botón de detener la grabación (botón de detener la grabación) cuando haya terminado.

      Mientras grabas, fíjate si aparecen barras azules en la línea de tiempo de asignación, como en la captura de pantalla de abajo.

      nuevas asignaciones

      Esas barras azules representan nuevas asignaciones de memoria. Esas nuevas asignaciones de memoria son sus candidatos a fugas de memoria. Puede hacer zoom en una barra para filtrar el panel Constructor para mostrar sólo los objetos que se asignaron durante el marco de tiempo especificado.

      línea de tiempo de asignación con zoom

      Despliegue el objeto y haga clic en su valor para ver más detalles sobre él en el panel Objeto. Por ejemplo, en la captura de pantalla de abajo, al ver los detalles del objeto que se acaba de asignar, podrás ver que se asignó a la variable x en el ámbito Window.

      detalles del objeto

      Investigar la asignación de memoria por función #

      Utiliza el tipo de perfilador de asignación de registros para ver la asignación de memoria por función de JavaScript.

      Perfilador de asignación de registros

      1. Selecciona el botón de opción Perfilador de asignación de registros. Si hay un trabajador en la página, puede seleccionarlo como objetivo de perfilado utilizando el menú desplegable junto al botón Iniciar.
      2. Pulse el botón Iniciar.
      3. Realice las acciones en la página que desee investigar.
      4. Pulse el botón Detener cuando haya terminado todas sus acciones.
      5. DevTools le muestra un desglose de la asignación de memoria por función. La vista por defecto es Heavy (Bottom Up), que muestra las funciones que asignaron la mayor cantidad de memoria en la parte superior.

        Perfil de asignación

        Detecta las recolecciones de basura frecuentes #

        Si tu página parece hacer pausas con frecuencia, entonces puedes tener problemas de recolección de basura.

        Puedes usar el Administrador de tareas de Chrome o los registros de memoria de la línea de tiempo para detectar las recolecciones de basura frecuentes. En el Administrador de tareas, los valores de memoria o de memoria JavaScript que aumentan y disminuyen con frecuencia representan recolecciones de basura frecuentes. En las grabaciones de la línea de tiempo, los gráficos de recuento de nodos o del montón de JS que suben y bajan con frecuencia indican colecciones de basura frecuentes.

        Una vez que haya identificado el problema, puede utilizar una grabación de la línea de tiempo de asignación para averiguar dónde se está asignando la memoria y qué funciones están causando las asignaciones.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *