Obtén información para grabar instantáneas del montón con Memoria > Perfiles > Instantánea del montón y encontrar fugas de memoria.
El generador de perfiles de montón muestra la distribución de la memoria según los objetos de JavaScript de tu página y los nodos DOM relacionados. Úsala para tomar instantáneas del 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 una página de la que deseas generar un perfil, abre DevTools y navega al panel Memoria.
- Selecciona el tipo de perfilación Heap snapshot , luego, selecciona una instancia de VM de JavaScript y haz clic en Take snapshot.
Cuando el panel Memoria carga y analiza la instantánea, muestra el tamaño total de los objetos de JavaScript accesibles debajo del título de la instantánea en la sección INSTANTES DEL MONTÓN.
Las instantáneas solo muestran los objetos del gráfico de memoria a los que se puede acceder desde el objeto global. Tomar una instantánea siempre comienza con la recolección de elementos no utilizados.
Borra instantáneas
Para quitar todas las instantáneas, haz clic en
Borrar todos los perfiles:Ver instantáneas
Para inspeccionar instantáneas desde diferentes perspectivas y con diferentes fines, selecciona una de las vistas del menú desplegable en la parte superior:
Ver | Contenido | Objetivo |
---|---|---|
Resumen | Objetos agrupados por nombres y fuentes de constructores. | Úsala para buscar objetos y su uso de memoria según el tipo. Es útil para hacer un seguimiento de las filtraciones 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. Para confirmar la presencia y la causa de una fuga de memoria, inspecciona el delta en la memoria liberada y el recuento de referencias. |
Contención | Contenido del montón | Proporciona una mejor vista de la estructura del objeto y ayuda a analizar los objetos a los que se hace referencia en el espacio de nombres global (ventana) para encontrar lo que los mantiene. Úsalo para analizar cierres y profundizar en tus objetos a un nivel bajo. |
Estadísticas | Gráfico circular de la asignación de memoria | Consulta los tamaños relativos de las partes de memoria asignadas al código, las cadenas, los arrays de JS, los arrays tipados y los objetos del sistema. |
Vista de resumen
Inicialmente, se abre una instantánea del montón en la vista Resumen que muestra una lista de Constructores en una columna. Los constructores se nombran según la función de JavaScript que creó el objeto, los nombres de los objetos simples se basan en las propiedades que contienen y algunos nombres son entradas especiales. Todos los objetos se agrupan primero por sus nombres y, luego, por la línea del archivo fuente de la que provienen, por ejemplo, source-file.js:line-number
.
Puedes expandir los constructores agrupados para ver los objetos de los que crearon instancias.
Para filtrar los constructores irrelevantes, escribe el nombre que deseas 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 mediante la ruta de nodos simple más corta.
- Tamaño superficial muestra la suma de los tamaños superficiales de todos los objetos creados por un constructor determinado. El tamaño superficial es el tamaño de la memoria que contiene un objeto. Por lo general, los arrays y las cadenas tienen tamaños superficiales más grandes. Consulta también Tamaños de los objetos.
- Tamaño retenido muestra el tamaño máximo retenido entre el mismo conjunto de objetos. El tamaño retenido es el tamaño de la memoria que puedes liberar si borras un objeto y haces que sus elementos dependientes ya no sean accesibles. Consulta también Tamaños de los objetos.
Cuando expandes un constructor, la vista Resumen muestra todas sus instancias. Cada instancia obtiene un desglose de sus tamaños superficiales y retenidos en las columnas correspondientes. El número que aparece después del carácter @
es el ID único del objeto. Te permite comparar instantáneas del montón por objeto.
Filtros de constructor
La vista Resumen te permite filtrar los constructores según casos comunes de uso ineficiente de la memoria.
Para usar estos filtros, selecciona una de las siguientes opciones en el menú desplegable de la derecha de la barra de acción:
- Todos los objetos: Todos los objetos capturados por la instantánea actual. Se establece 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 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.
- Cadena duplicada: Son valores de cadena que se almacenaron varias veces en la memoria.
- Objetos retenidos por nodos separados: Son objetos que se mantienen activos porque un nodo DOM separado hace referencia a ellos.
- Objetos retenidos por la consola de Herramientas para desarrolladores: Son objetos que se mantienen en la memoria porque se evaluaron o interactuaron con ellos a través de la consola de Herramientas para desarrolladores.
Entradas especiales en Resumen
Además de agrupar por constructores, la vista Resumen también agrupa objetos por los siguientes criterios:
- 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
- Son categorías especiales que no se basan en constructores.
(array)
Esta categoría incluye varios objetos internos similares a arrays que no corresponden directamente a 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 ejecutar funciones definidas por JavaScript o WebAssembly. Cada función se puede representar de diferentes maneras, desde pequeña y lenta hasta grande y rápida.
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 esa función para que se ejecute más rápido. Si una función no se ejecuta desde hace un tiempo, es posible que V8 borre los datos internos de esa función.
(concatenated string)
Cuando V8 concatena dos cadenas, como con el operador +
de JavaScript, puede elegir representar el resultado de forma interna como una "cadena concatenada", también conocida como la estructura de datos Rope.
En lugar de copiar todos los caracteres de las dos cadenas de origen en una nueva, V8 asigna un objeto pequeño con campos internos llamados first
y second
, que apuntan a las dos cadenas de origen. Esto permite que V8 ahorre 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 de C++, usa Chrome for Testing y haz lo siguiente:
- Abre DevTools y activa Settings > Experiments > Show option to expose internals in heap snapshots.
- Abre el panel Memory, selecciona Heap snapshot y activa Expose internals (includes additional implementation-specific details).
- Reproduce el problema que causaba que
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 Fast Properties in V8, V8 realiza un seguimiento de las clases ocultas (o formas) para que se puedan representar de manera eficiente varios objetos con las mismas propiedades en el mismo orden. Esta categoría contiene esas clases ocultas, llamadas system / Map
(no relacionadas con Map
de JavaScript), y los datos relacionados.
(sliced string)
Cuando V8 necesita tomar una subcadena, como cuando el código de JavaScript llama a String.prototype.substring()
, V8 puede optar por asignar un objeto cadena cortada 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. Si una cadena cortada retiene mucha memoria, es posible que el programa haya activado el problema 2869 y que sea conveniente tomar medidas deliberadas para “aplanar” la cadena cortada.
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 al Context
en el que se ejecuta para que pueda acceder a esas variables. Aunque los objetos Context
no son directamente visibles desde JavaScript, tienes 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 Comparación te permite encontrar objetos filtrados comparando varias instantáneas entre sí. Por ejemplo, realizar una acción y revertirla, como abrir un documento y cerrarlo, no debe dejar objetos adicionales.
Para verificar que una operación determinada no cree filtraciones, haz lo siguiente:
- Toma una instantánea del montón antes de realizar una operación.
- Realizar una operación Es decir, interactúa con una página de alguna manera que creas que podría estar causando una filtración.
- Realiza una operación inversa. Es decir, haz la interacción opuesta y repítela varias veces.
- Toma una segunda instantánea del montón y cambia su vista a Comparación, y compárala con la Instantánea 1.
La vista Comparación muestra la diferencia entre dos instantáneas. Cuando se expande una entrada de total, se muestran las instancias de objetos agregadas y borradas:
Vista de contención
La vista Containment es una "vista panorámica" de la estructura de objetos de tu aplicación. Te permite ver dentro de los cierres de funciones, observar los objetos internos de la VM que, en conjunto, conforman tus objetos de JavaScript y comprender cuánta memoria usa tu aplicación en un nivel muy bajo.
La vista proporciona varios puntos de entrada:
- Objetos DOMWindow. Objetos globales para el código JavaScript.
- Raíces de GC. Raíces de GC que usa el recolector de basura 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 DOM y reglas CSS.
La sección Retenedores
En la sección Retenedores, en la parte inferior del panel Memoria, se muestran los objetos que apuntan al objeto seleccionado en la vista. El panel Memoria actualiza la sección Retenedores cuando seleccionas objetos diferentes en cualquiera de las vistas, excepto Estadísticas.
En este ejemplo, la propiedad x
de una instancia de Item
retiene la cadena seleccionada.
Ignora los retenedores
Puedes ocultar los retenedores para saber si algún otro objeto retiene el seleccionado. Con esta opción, no tienes que quitar primero este retenedor del código y, luego, volver 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 omitidos se marcan como ignored
en la columna Distancia. Para dejar de ignorar todos los retenedores, haz clic en Restore ignored retainers en la barra de acciones de la parte superior.
Cómo encontrar un objeto específico
Para encontrar un objeto en el montón recopilado, puedes usar Ctrl + F y, luego, ingresar el ID del objeto.
Asigna nombres a las funciones para distinguir los cierres
Es muy útil nombrar las funciones para que puedas distinguir entre los 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;
}
Mientras que este ejemplo 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 de DOM
El generador de perfiles de montón puede reflejar dependencias bidireccionales entre objetos nativos del navegador (nodos DOM y reglas CSS) y objetos de JavaScript. Esto ayuda a descubrir fugas invisibles que se producen debido a subárboles DOM desconectados olvidados que flotan.
Las filtraciones de DOM pueden ser más grandes de lo que crees. Considera el siguiente ejemplo: ¿Cuándo se recolecta el elemento no utilizado #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 forma recursiva, hasta #tree
, por lo que solo cuando leafRef
se anula, el árbol completo debajo de #tree
es un candidato para GC.