Tutorial: Buscar pérdidas de memoria (JavaScript)
Este tutorial te guía por el proceso de identificar y corregir un problema simple de memoria con el analizador de memoria de JavaScript. El analizador de memoria de JavaScript está disponible en Visual Studio para las aplicaciones de la Tienda Windows compiladas para Windows que usan JavaScript. En este escenario, crearás una aplicación que conserva incorrectamente elementos DOM en memoria en lugar de eliminarlos a la misma velocidad a la que se crearon.
Aunque la causa de la pérdida de memoria es muy específica en esta aplicación, los pasos que se muestran aquí indican un flujo de trabajo que suele ser eficaz para aislar los objetos con pérdida de memoria.
Ejecutar la aplicación de prueba del analizador de memoria de JavaScript
En Visual Studio, elige Archivo, Nuevo, Proyecto.
Elija JavaScript en el panel izquierdo y, a continuación, elija Aplicaciones Windows, Aplicaciones universales o Aplicaciones Windows Phone.
Elija la plantilla de proyecto Aplicación vacía en el panel central.
En el cuadro Nombre, especifica un nombre como JS_Mem_Tester y elige Aceptar.
En el Explorador de soluciones, abre default.html y pega el siguiente código entre las etiquetas <body>:
<div class="wrapper"> <div id="item"></div> <button class="memleak" style="display: block" >Leak Memory</button> </div>
Importante
Si utiliza una plantilla de aplicación universal, necesita actualizar el código HTML y CSS en los proyectos .Windows y .WindowsPhone.
Abre default.css y agrega el código CSS siguiente:
.memleak { position: absolute; top: 100px; left: 100px; }
Abre default.js y reemplaza todo el código con este código:
(function () { "use strict"; var app = WinJS.Application; var activation = Windows.ApplicationModel.Activation; var wrapper; var elem; app.onactivated = function (args) { if (args.detail.kind === activation.ActivationKind.launch) { if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) { } else { } args.setPromise(WinJS.UI.processAll()); elem = document.getElementById("item"); wrapper = document.querySelector(".wrapper"); var btn = document.querySelector(".memleak"); btn.addEventListener("click", btnHandler); run(); } }; app.oncheckpoint = function (args) { }; app.start(); function run() { initialize(); load(); } function initialize() { if (wrapper != null) { elem.removeNode(true); } } function load() { var newDiv = document.createElement("div"); newDiv.style.zIndex = "-1"; newDiv.id = "item"; wrapper.appendChild(newDiv); } function btnHandler(args) { run(); } })();
Elige la tecla F5 para iniciar la depuración. Comprueba que el botón Leak Memory aparece en la página.
Vuelve a Visual Studio (Alt+Tab) y presiona Mayús+F5 para detener la depuración.
Ahora que has comprobado que la aplicación funciona, puedes examinar el uso de memoria.
Analizar el uso de memoria
En la barra de herramientas Depurar, en la lista Iniciar depuración, elige el destino de depuración del proyecto actualizado: los emuladores de Windows Phone o Simulador.
Sugerencia
Para una aplicación de la Tienda Windows, también puedes elegir Equipo local o Equipo remoto en esta lista.Sin embargo, la ventaja de utilizar el emulador o simulador es que puede colocarlo junto a Visual Studio y cambiar fácilmente entre la aplicación en ejecución y el analizador de memoria de JavaScript.Para obtener más información, consulte Ejecutar aplicaciones de la Tienda desde Visual Studio y Ejecutar aplicaciones de la Tienda Windows en un equipo remoto desde Visual Studio.
En el menú Depurar, elige Rendimiento y diagnósticos.
En Herramientas disponibles, elige Memoria de JavaScript e Iniciar.
En este tutorial, asociarás el analizador de memoria al proyecto de inicio. Para obtener información sobre otras opciones, como adjuntar el analizador de memoria a una aplicación instalada, consulte Analizar el uso de memoria (JavaScript).
Al iniciar el analizador de memoria, puede aparecer un Control de cuentas de usuario que solicite tu permiso para ejecutar VsEtwCollector.exe. Elige Sí.
Elige el botón Leak Memory cuatro veces seguidas.
Cuando eliges el botón, el código de control de eventos de default.js funciona de tal modo que producirá una pérdida de memoria. Lo usarás con fines de diagnóstico.
Sugerencia
Al repetir el escenario que deseas probar para una pérdida de memoria se simplifica el filtrado de información que no interesa, como los objetos que se agregan al montón durante la inicialización de la aplicación o cuando se carga una página.
Desde la aplicación en ejecución, cambia a Visual Studio (Alt+Tab).
El analizador de memoria de JavaScript muestra información en una nueva pestaña en Visual Studio.
El gráfico de memoria de esta vista de resumen muestra el uso de memoria de proceso a lo largo del tiempo. La vista también proporciona comandos como Tomar instantánea de montón. Una instantánea proporciona información detallada sobre el uso de memoria en un momento determinado. Para obtener más información, consulte Analizar el uso de memoria (JavaScript).
Elige Tomar instantánea de montón.
Cambia a la aplicación y elige Leak Memory.
Cambia a Visual Studio y elige de nuevo Tomar instantánea de montón.
En esta ilustración se muestra la instantánea de referencia (1) y la instantánea 2.
Nota
El emulador de Windows Phone no muestra una captura de pantalla de la aplicación cuando se realizó la instantánea.
Cambia a la aplicación y vuelve a elegir el botón Leak Memory.
Cambia a Visual Studio y elige Tomar instantánea de montón por tercera vez.
Sugerencia
Al tomar una tercera instantánea en este flujo de trabajo, puedes filtrar los cambios de la instantánea de línea de base a la segunda instantánea que no estén asociados con pérdidas de memoria.Por ejemplo, puede haber cambios esperados, como la actualización de encabezados y pies de página en una página. Esto generará algunos cambios en cuanto al uso de la memoria, pero puede que no estén relacionados con pérdidas de memoria.
En esta ilustración se muestra la instantánea 2 y la instantánea 3.
En Visual Studio, elige Detener para detener la generación de perfiles.
En Visual Studio, compara las instantáneas. En la instantánea 2 se muestra lo siguiente:
El tamaño del montón (indicado por la flecha arriba de color rojo a la izquierda) ha aumentado en varios kB en comparación con el de la instantánea 1.
Importante
Los valores de uso de memoria exactos para el tamaño del montón dependen del destino de depuración.
El número de objetos del montón (indicado por la flecha arriba de color rojo a la derecha) ha aumentado con respecto al de la instantánea 1. Se agregó un objeto (+1) y no se quitó ninguno (-0).
En la instantánea 3 se muestra lo siguiente:
El tamaño del montón ha aumentado de nuevo en varios cientos de bytes en comparación con el de la instantánea 2.
El número de objetos del montón también ha aumentado en comparación con el de la instantánea 2. Se agregó un objeto (+1) y no se quitó ninguno (-0).
En la instantánea 3, elija el texto del vínculo de la derecha, que muestra un valor de +1 / -0 junto a la flecha arriba de color rojo.
Se abrirá una vista de diferencias de los objetos en el montón, denominada Instantánea 3 - Instantánea 2, en la que se muestra la vista Tipos de forma predeterminada. De manera predeterminada, se ve una lista de los objetos agregados al montón entre las instantáneas 2 y 3.
En el filtro Ámbito, elige Objetos dejados de la instantánea nº 2.
Abre el objeto HTMLDivElement en la parte superior del árbol de objetos, mostrado aquí.
Esta vista muestra información útil sobre la pérdida de memoria, como la siguiente:
Esta vista muestra un elemento DIV con un id. item, y el tamaño retenido del objeto es de varios cientos de bytes (el valor exacto puede variar).
Este es un objeto sobrante de la instantánea 2 y representa una posible pérdida de memoria.
En este punto puede ser útil conocer algo de la aplicación: al elegir el botón Leak Memory, se debería quitar un elemento DIV y agregarse un elemento, por lo que el código parece que no funciona bien, es decir, hay una pérdida de memoria. En la sección siguiente se explica cómo solucionar esto.
Sugerencia
A veces, la ubicación de un objeto con respecto al objeto Global puede ayudar a identificar ese objeto.Para ello, abre el menú contextual del identificador y elige Mostrar en vista de raíces.
Corregir el problema de memoria
Con los datos que revela el generador de perfiles, se examina el código responsable de quitar los elementos DOM cuyo id. sea "item". Esto se produce en la función initialize().
function initialize() { if (wrapper != null) { elem.removeNode(true); } }
elem.removeNode(true) quizás no funciona bien. Examinas el modo en que el código almacena en caché el elemento DOM y detectas un problema: la referencia al elemento almacenado en caché no se actualiza.
En default.js, agrega la siguiente línea de código a la función de carga, justo antes de la llamada a appendChild:
elem = newDiv;
Este código actualiza la referencia al elemento almacenado en caché para que el elemento se quite bien al elegir el botón Leak Memory. El código completo de la función de carga tiene ahora el siguiente aspecto:
function load() { wrapper = document.querySelector(".wrapper"); var newDiv = document.createElement("div"); newDiv.style.zIndex = "-1"; newDiv.id = "item"; elem = newDiv; wrapper.appendChild(newDiv); }
En el menú Depurar, elige Rendimiento y diagnósticos.
En Herramientas disponibles, elige Memoria de JavaScript e Iniciar.
Sigue el mismo procedimiento anterior para tomar tres instantáneas. Aquí se resumen los pasos:
En la aplicación, elige el botón Leak Memory cuatro veces seguidas.
Cambia a Visual Studio y elige Tomar instantánea de montón para la instantánea de referencia.
En la aplicación, elige el botón Leak Memory.
Cambia a Visual Studio y elige Tomar instantánea de montón para la segunda instantánea.
En la aplicación, elige el botón Leak Memory.
Cambia a Visual Studio y elige Tomar instantánea de montón para la tercera instantánea.
La instantánea 3 ahora muestra el tamaño del montón como Sin aumento con respecto a la instantánea 2, y el recuento de objetos como +1 / -1, lo que indica que se ha agregado un objeto y se ha quitado otro. Este es el comportamiento deseado.
En la ilustración siguiente se muestra la instantánea 2 y la instantánea 3.