Aprende a registrar instantáneas de montón con Memoria > Perfiles > Instantánea de montón y a encontrar fugas de memoria.
El generador de perfiles del montón muestra la distribución de la memoria realizada por los objetos JavaScript de la página y los nodos del DOM relacionados. Úsalo para tomar instantáneas de montón de JS, analizar gráficos de memoria, comparar instantáneas y encontrar fugas de memoria. Para obtener más información, consulta Árbol de retención de objetos.
Tomar una instantánea
Para tomar una instantánea del montón, haz lo siguiente:
- En la página para la que quieras generar un perfil, abre Herramientas para desarrolladores y navega al panel Memory.
- Selecciona el tipo de perfil Instantánea de montón, luego selecciona una instancia de VM de JavaScript y haz clic en Tomar instantánea.
Cuando el panel Memory carga y analiza la instantánea, muestra el tamaño total de los objetos JavaScript accesibles debajo del título de la instantánea, en la sección INSTRUCCIONES DE HEAP.
Las instantáneas muestran solo los objetos del gráfico de memoria a los que se puede acceder desde el objeto global. La toma de una instantánea siempre comienza con la recolección de elementos no utilizados.
Borrar instantáneas
Para quitar todas las instantáneas, haz clic en
Clear all profiles:Ver instantáneas
Si quieres inspeccionar las instantáneas desde diferentes perspectivas para distintos fines, selecciona una de las vistas en el menú desplegable ubicado en la parte superior:
Ver | Contenido | Objetivo |
---|---|---|
Resumen | Objetos agrupados por nombres de constructores. | Úsala para encontrar objetos y el uso que hacen de la memoria según el tipo. Es útil para hacer un seguimiento de las fugas del DOM. |
Comparación | Diferencias entre dos instantáneas | Úsala para comparar dos (o más) instantáneas, antes y después de una operación. Confirma la presencia y la causa de una fuga de memoria inspeccionando el delta en la memoria liberada y el recuento de referencias. |
Contención | Contenido del montón | Proporciona una mejor vista de la estructura de objetos y ayuda a analizar los objetos a los que se hace referencia en el espacio de nombres global (ventana) para descubrir qué los mantiene. Úsala para analizar cierres y examinar los objetos en un nivel bajo. |
Estadísticas | Gráfico circular de la asignación de memoria | Consulta los tamaños reales de las partes de la memoria asignadas al código, las cadenas, los arrays de JS, los arrays escritos y los objetos del sistema. |
Vista de resumen
Inicialmente, se abre una instantánea del montón en la vista Summary que enumera los Constructors en una columna. Puedes expandir los constructores para ver los objetos de los que crearon instancias.
Para filtrar los constructores irrelevantes, escribe un nombre que quieras inspeccionar en el filtro de clase en la parte superior de la vista Resumen.
Los números junto a los nombres de los constructores indican la cantidad total de objetos creados con el constructor. La vista Resumen también muestra las siguientes columnas:
- Distancia: Muestra la distancia a la raíz con la ruta de nodos más corta y simple.
- En Tamaño superficial, se muestra la suma de tamaños aplanados de todos los objetos creados por un constructor determinado. El tamaño superficial es el tamaño de la memoria que retiene un objeto en sí mismo. En general, los arrays y las cadenas tienen tamaños superficiales más grandes. Consulta también Tamaños de objetos.
- En Tamaño retenido, se muestra el tamaño retenido máximo en el mismo conjunto de objetos. El tamaño retenido es el tamaño de memoria que puedes liberar borrando un objeto y haciendo que ya no se pueda acceder a sus dependientes. Consulta también Tamaños de objetos.
Cuando expandes un constructor, la vista Summary muestra todas sus instancias. Cada instancia obtiene un desglose de sus tamaños superficiales y retenidos en las columnas correspondientes. El número después del carácter @
es el ID único del objeto. Te permite comparar capturas de pantalla de montón por objeto.
Filtros del constructor
La vista Resumen te permite filtrar los constructores en función de casos comunes de uso ineficiente de la memoria.
Para utilizar estos filtros, selecciona una de las siguientes opciones en el menú desplegable que se encuentra en el extremo derecho de la barra de acciones:
- Todos los objetos: Todos los objetos capturados por la instantánea actual. Establecida de forma predeterminada.
- Objetos asignados antes de la instantánea 1: Son los objetos que se crearon y permanecieron en la memoria antes de que se tomara la primera instantánea.
- Objetos asignados entre las Instantáneas 1 y las Instantáneas 2: Consulta la diferencia en los objetos entre la instantánea más reciente y la anterior. Cada instantánea nueva agrega un incremento de este filtro a la lista desplegable.
- Strings duplicadas: Son valores de strings que se almacenaron varias veces en la memoria.
- Objetos retenidos por nodos separados: Son objetos que se mantienen activos porque un nodo del DOM desconectado hace referencia a ellos.
- Objetos retenidos por la consola de Herramientas para desarrolladores: Son objetos que se conservan en la memoria porque se evaluaron o interactuaron con ellos a través de la consola de Herramientas para desarrolladores.
Entradas especiales en el resumen
Además de agrupar por constructores, la vista Summary también agrupa objetos por:
- Funciones integradas, como
Array
oObject
- Elementos HTML agrupados por sus etiquetas, por ejemplo,
<div>
,<a>
,<img>
y otros - Las funciones que definiste en tu código
- Categorías especiales que no se basan en constructores.
(array)
Esta categoría incluye varios objetos internos similares a un array que no corresponden directamente a los objetos visibles en JavaScript.
Por ejemplo, el contenido de los objetos Array
de JavaScript se almacena en un objeto interno secundario llamado (object elements)[]
para permitir un cambio de tamaño más fácil. Del mismo modo, las propiedades con nombre en los objetos de JavaScript suelen almacenarse en objetos internos secundarios llamados (object properties)[]
que también se incluyen en la categoría (array)
.
(compiled code)
Esta categoría incluye datos internos que V8 necesita para poder ejecutar funciones definidas por JavaScript o WebAssembly. Cada función se puede representar de varias maneras, desde pequeñas y lentas hasta grandes y rápidas.
V8 administra automáticamente el uso de memoria en esta categoría. Si una función se ejecuta muchas veces, V8 usa más memoria para poder ejecutarse más rápido. Si una función no se ejecutó por un tiempo, es posible que V8 borre sus datos internos.
(concatenated string)
Cuando V8 concatena dos cadenas, como con el operador +
de JavaScript, puedes elegir representar el resultado internamente como una "cadena concatenada". también conocida como estructura de datos Rope.
En lugar de copiar todos los caracteres de las dos cadenas de origen en una cadena nueva, V8 asigna un objeto pequeño con campos internos llamados first
y second
, que apuntan a las dos cadenas de origen. Esto le permite a V8 ahorrar tiempo y memoria. Desde la perspectiva del código JavaScript, estas son solo cadenas normales y se comportan como cualquier otra.
InternalNode
Esta categoría representa objetos asignados fuera de V8, como los objetos C++ definidos por Blink.
Para ver los nombres de las clases C++, usa Chrome for Testing y haz lo siguiente:
- Abre las Herramientas para desarrolladores y activa la Configuración > Experimentos > Mostrar opción para exponer componentes internos en instantáneas de montón.
- Abre el panel Memoria, selecciona Instantánea de montón y activa Exponer componentes internos (incluye detalles adicionales específicos de la implementación).
- Reproduce el problema que provocó que el
InternalNode
retuviera mucha memoria. - Toma una instantánea del montón. En esta instantánea, los objetos tienen nombres de clase C++ en lugar de
InternalNode
.
(object shape)
Como se describe en Propiedades rápidas de V8, V8 rastrea clases ocultas (o formas) para que varios objetos con las mismas propiedades en el mismo orden se puedan representar de manera eficiente. Esta categoría contiene esas clases ocultas, llamadas system / Map
(no relacionadas con Map
de JavaScript), y datos relacionados.
(sliced string)
Cuando V8 necesita tomar una subcadena, como cuando el código JavaScript llama a String.prototype.substring()
, es posible que V8 elija asignar un objeto de cadena dividida en lugar de copiar todos los caracteres relevantes de la cadena original. Este objeto nuevo contiene un puntero a la cadena original y describe qué rango de caracteres de la cadena original se debe usar.
Desde la perspectiva del código JavaScript, estas son solo cadenas normales y se comportan como cualquier otra cadena. Si una cadena cortada retiene mucha memoria, es posible que el programa haya activado el error 2869 y podría beneficiarse de tomar medidas deliberadas para "compactar". la cadena dividida.
system / Context
Los objetos internos de tipo system / Context
contienen variables locales de un cierre: un alcance de JavaScript al que puede acceder una función anidada.
Cada instancia de función contiene un puntero interno a la Context
en la que se ejecuta, de modo que pueda acceder a esas variables. Si bien los objetos Context
no son directamente visibles en JavaScript, tienes un control directo sobre ellos.
(system)
Esta categoría contiene varios objetos internos que aún no se categorizaron de una manera más significativa.
Vista de comparación
La vista Comparison te permite encontrar objetos filtrados comparando varias instantáneas entre sí. Por ejemplo, realizar una acción e revertirla, como abrir un documento y cerrarlo, no debería dejar objetos adicionales.
Para verificar que una operación determinada no cree fugas, haz lo siguiente:
- Toma una instantánea del montón antes de realizar una operación.
- Realiza una operación. Es decir, puedes interactuar con una página de alguna manera que creas que puede estar causando una fuga.
- Realiza una operación inversa. Es decir, realiza la interacción opuesta y repítela varias veces.
- Toma una segunda instantánea del montón y cambia su vista a Comparison (comparación) con Instantánea 1.
En la vista Comparison, se muestra la diferencia entre dos capturas de pantalla. Cuando se expande un total entrada, se muestran las instancias de objetos agregados y borrados:
Vista de contención
La vista Containment es una vista general. de la estructura de objetos de tu aplicación. Te permite echar un vistazo a cierres de funciones, observar objetos internos de VM que forman tus objetos de JavaScript y comprender cuánta memoria usa tu aplicación a un nivel muy bajo.
La vista proporciona varios puntos de entrada:
- Objetos DOMWindow. Objetos globales para código JavaScript
- Raíces del GC. Raíces de GC que usa el recolector de elementos no utilizados de la VM. Las raíces de GC pueden consistir en mapas de objetos integrados, tablas de símbolos, pilas de subprocesos de VM, cachés de compilación, alcances de controladores y controladores globales.
- Objetos nativos. Objetos del navegador "enviados" dentro de la máquina virtual de JavaScript para permitir la automatización; por ejemplo, nodos del DOM y reglas de CSS.
La sección Contratos de servicio
En la sección Retainers en la parte inferior del panel Memory, se muestran objetos que apuntan al objeto seleccionado en la vista. El panel Memory (Memoria) actualiza la sección Retainers cuando seleccionas objetos diferentes en cualquiera de las vistas, excepto Statistics.
En este ejemplo, la propiedad x
de una instancia Item
retiene la cadena seleccionada.
Ignorar retenedores
Puedes ocultar los retenedores para descubrir qué otros objetos retienen el seleccionado. Con esta opción, no es necesario que primero quites este retenedor del código y que luego vuelvas a tomar la instantánea del montón.
Para ocultar un retenedor, haz clic con el botón derecho y selecciona Ignorar este retenedor. Los retenedores ignorados se marcan como ignored
en la columna Distance. Para dejar de ignorar todos los retenedores, haz clic en Restaurar los retenedores ignorados en la barra de acciones en la parte superior.
Encuentra un objeto específico
Para encontrar un objeto en el montón recopilado, puedes realizar una búsqueda con Ctrl + F y, luego, ingresar el ID del objeto.
Nombrar funciones para distinguir cierres
Resulta muy útil nombrar las funciones para que puedas distinguir entre cierres en la instantánea.
Por ejemplo, el siguiente código no usa funciones con nombre:
function createLargeClosure() {
var largeStr = new Array(1000000).join('x');
var lC = function() { // this is NOT a named function
return largeStr;
};
return lC;
}
En cambio, en este ejemplo, se hace lo siguiente:
function createLargeClosure() {
var largeStr = new Array(1000000).join('x');
var lC = function lC() { // this IS a named function
return largeStr;
};
return lC;
}
Descubre fugas del DOM
El generador de perfiles de montón puede reflejar dependencias bidireccionales entre objetos nativos del navegador (nodos del DOM y reglas de CSS) y objetos de JavaScript. Esto ayuda a descubrir fugas que, de otro modo, serían invisibles y que se producen debido a subárboles del DOM separados que quedan dando vueltas.
Las fugas del DOM pueden ser más grandes de lo que crees. Considera el siguiente ejemplo: ¿Cuándo se recoge la basura de #tree
?
var select = document.querySelector;
var treeRef = select("#tree");
var leafRef = select("#leaf");
var body = select("body");
body.removeChild(treeRef);
//#tree can't be GC yet due to treeRef
treeRef = null;
//#tree can't be GC yet due to indirect
//reference from leafRef
leafRef = null;
//#NOW #tree can be garbage collected
#leaf
mantiene una referencia a su elemento superior (parentNode
) y, de manera recursiva, hasta #tree
, por lo que solo cuando se anula leafRef
, el árbol completo debajo de #tree
es un candidato para la GC.