Obtén información para medir el uso de memoria de tu página web en producción para detectar regresiones.
Los navegadores administran la memoria de las páginas web automáticamente. Cuando una página web crea un objeto, el navegador asigna un fragmento de memoria “detrás de escena” a almacenar el objeto. Como la memoria es un recurso finito, el navegador realiza de elementos no utilizados para detectar cuándo un objeto ya no es necesario y el bloque de memoria subyacente.
Sin embargo, la detección no es perfecta se demostró que la detección perfecta es una tarea imposible. Por lo tanto, los navegadores se aproximan a la noción de "un objeto si la solicitud no se encuentra aquí". con la noción de “un objeto es accesible”. Si la página web no puede alcance un objeto a través de sus variables y los campos de otros objetos accesibles, el navegador podrá reclamar el objeto de forma segura. La diferencia entre estos dos nociones conduce a fugas de memoria, como se ilustra en el siguiente ejemplo.
const object = {a: new Array(1000), b: new Array(2000)};
setInterval(() => console.log(object.a), 1000);
Aquí ya no se necesita el array más grande b
, pero el navegador no lo necesita.
y recupéralo, ya que aún se puede acceder a él mediante object.b
en la devolución de llamada. Por lo tanto,
se pierde la memoria del array más grande.
Las fugas de memoria son prevalentes en la Web. Es fácil introducir uno si olvidas cancelar el registro de un objeto de escucha de eventos, capturando objetos accidentalmente de un iframe, al no cerrar un trabajador, la acumulación de objetos en arrays, etcétera. Si una página web tiene fugas de memoria, el uso de memoria aumenta con el tiempo y la página web parece lenta inflado a los usuarios.
El primer paso para resolver este problema es medirlo. La nueva herramienta
La API de performance.measureUserAgentSpecificMemory()
permite que los desarrolladores
que miden el uso de memoria de sus páginas web en producción y, por lo tanto, detectan la memoria
que pasan por las pruebas locales.
¿En qué se diferencia performance.measureUserAgentSpecificMemory()
de la API de performance.memory
heredada?
Si conoces la API no estándar de performance.memory
existente,
Quizá te preguntes en qué se diferencia la nueva API. La principal diferencia es
que la API anterior devuelve el tamaño del montón de JavaScript, mientras que la API nueva
calcula la memoria usada por la página web. Esta diferencia se convierte
importante cuando Chrome comparte el mismo montón con varias páginas web (o
varias instancias de la misma página web). En tales casos, el resultado de la configuración
La API puede estar desactivada de forma arbitraria. Dado que la API anterior se define en
términos específicos de la implementación, como "montón", y estandarizarlo no tiene sentido.
Otra diferencia es que la nueva API realiza la medición de la memoria durante la recolección de elementos no utilizados. Esto reduce el ruido en los resultados, pero puede tardar un hasta que se producen los resultados. Ten en cuenta que otros navegadores pueden decidir implementar la nueva API sin depender de la recolección de elementos no utilizados.
Casos de uso sugeridos
El uso de memoria de una página web depende del tiempo de los eventos, de las acciones del usuario y recolecciones de elementos no utilizados. Por eso, la API de medición de memoria está diseñada para agregar datos de uso de memoria desde la producción. Los resultados de llamadas individuales son menos útiles. Casos prácticos de ejemplo:
- Detección de regresión durante el lanzamiento de una versión nueva de la página web para detectar nuevas fugas de memoria.
- Realiza pruebas A/B de una función nueva para evaluar su impacto en la memoria y detectar fugas de memoria.
- Correlaciona el uso de memoria con la duración de la sesión para verificar la presencia o ausencia de fugas de memoria.
- Correlaciona el uso de memoria con las métricas del usuario para comprender el impacto general del uso de memoria.
Compatibilidad del navegador
Actualmente, la API solo es compatible con los navegadores basados en Chromium a partir de Chrome 89. El resultado de la API depende en gran medida de la implementación porque los navegadores tienen las diferentes formas de representar objetos en la memoria y las diferentes formas la estimación del uso de memoria. Los navegadores pueden excluir algunas regiones de la memoria de contabilizar si una contabilidad adecuada es demasiado costosa o inviable. Por lo tanto, los resultados no se pueden comparar entre navegadores. Solo tiene sentido comparar resultados en el mismo navegador.
Usa performance.measureUserAgentSpecificMemory()
Detección de funciones
La función performance.measureUserAgentSpecificMemory
no estará disponible o es posible que
fallan con un SecurityError si el entorno de ejecución no cumple
los requisitos de seguridad para prevenir filtraciones
de información de origen cruzado.
Se basa en el aislamiento de origen cruzado, que una página web puede activar.
estableciendo encabezados COOP+COEP.
La compatibilidad se puede detectar en el entorno de ejecución:
if (!window.crossOriginIsolated) {
console.log('performance.measureUserAgentSpecificMemory() is only available in cross-origin-isolated pages');
} else if (!performance.measureUserAgentSpecificMemory) {
console.log('performance.measureUserAgentSpecificMemory() is not available in this browser');
} else {
let result;
try {
result = await performance.measureUserAgentSpecificMemory();
} catch (error) {
if (error instanceof DOMException && error.name === 'SecurityError') {
console.log('The context is not secure.');
} else {
throw error;
}
}
console.log(result);
}
Pruebas locales
Chrome realiza la medición de la memoria durante la recolección de elementos no utilizados, lo que significa que la API no resuelva inmediatamente la promesa de resultado y espere para la próxima recolección de elementos no utilizados.
Llamar a la API fuerza la recolección de elementos no utilizados después de un tiempo de espera, que se
que actualmente está establecido en 20 segundos, aunque puede suceder antes. Iniciar Chrome con la
La marca de línea de comandos de --enable-blink-features='ForceEagerMeasureMemory'
reduce
el tiempo de espera a cero y es útil para pruebas y depuración locales.
Ejemplo
El uso recomendado de la API es definir un monitor de memoria global que
muestra el uso de la memoria de toda la página web y envía los resultados a un servidor.
para la agregación y el análisis. La forma más sencilla es muestrear de forma periódica, por
ejemplo cada M
minutos. Sin embargo, eso introduce sesgos en los datos porque
pueden ocurrir picos de memoria entre las muestras.
En el siguiente ejemplo, se muestra cómo hacer mediciones de memoria imparciales con un proceso Poisson, que garantiza que las muestras tengan la misma probabilidad de ocurrir en cualquier momento (demostración, fuente).
Primero, define una función que programe la siguiente medición de memoria usando
setTimeout()
con un intervalo aleatorizado
function scheduleMeasurement() {
// Check measurement API is available.
if (!window.crossOriginIsolated) {
console.log('performance.measureUserAgentSpecificMemory() is only available in cross-origin-isolated pages');
console.log('See https://web.dev/coop-coep/ to learn more')
return;
}
if (!performance.measureUserAgentSpecificMemory) {
console.log('performance.measureUserAgentSpecificMemory() is not available in this browser');
return;
}
const interval = measurementInterval();
console.log(`Running next memory measurement in ${Math.round(interval / 1000)} seconds`);
setTimeout(performMeasurement, interval);
}
La función measurementInterval()
calcula un intervalo aleatorio en milisegundos.
para que, en promedio, haya una medición cada cinco minutos. Consulta Exponencial
distribución si te interesan los cálculos detrás de la función.
function measurementInterval() {
const MEAN_INTERVAL_IN_MS = 5 * 60 * 1000;
return -Math.log(Math.random()) * MEAN_INTERVAL_IN_MS;
}
Por último, la función performMeasurement()
asíncrona invoca la API, los registros
el resultado y programa la siguiente medición.
async function performMeasurement() {
// 1. Invoke performance.measureUserAgentSpecificMemory().
let result;
try {
result = await performance.measureUserAgentSpecificMemory();
} catch (error) {
if (error instanceof DOMException && error.name === 'SecurityError') {
console.log('The context is not secure.');
return;
}
// Rethrow other errors.
throw error;
}
// 2. Record the result.
console.log('Memory usage:', result);
// 3. Schedule the next measurement.
scheduleMeasurement();
}
Por último, empieza a medir.
// Start measurements.
scheduleMeasurement();
El resultado puede verse de la siguiente manera:
// Console output:
{
bytes: 60_100_000,
breakdown: [
{
bytes: 40_000_000,
attribution: [{
url: 'https://example.com/',
scope: 'Window',
}],
types: ['JavaScript']
},
{
bytes: 20_000_000,
attribution: [{
url: 'https://example.com/iframe',
container: {
id: 'iframe-id-attribute',
src: '/iframe',
},
scope: 'Window',
}],
types: ['JavaScript']
},
{
bytes: 100_000,
attribution: [],
types: ['DOM']
},
],
}
La estimación del uso total de memoria se muestra en el campo bytes
. Este valor es de
depende en gran medida de la implementación y no se puede comparar entre navegadores. Puede
incluso cambiar entre diferentes versiones del mismo navegador. El valor incluye
Memoria JavaScript y DOM de todos los iframes, las ventanas relacionadas y los trabajadores web de
el proceso actual.
En la lista breakdown
, se proporciona más información sobre la memoria usada. Cada
describe una parte de la memoria y la atribuye a un conjunto de
ventanas, iframes y trabajadores identificados por URL. El campo types
enumera
los tipos de memoria específicos de la implementación
asociados con la memoria.
Es importante tratar todas las listas de forma genérica y no codificar
en función de un navegador en particular. Por ejemplo, es posible que algunos navegadores
Se muestra un breakdown
vacío o un attribution
vacío. Es posible que otros navegadores
mostrar varias entradas en attribution
que indican que no pudieron distinguir
cuál de estas entradas posee la memoria.
Comentarios
Al grupo de la comunidad de rendimiento web y al equipo de Chrome les encantaría
conocer tus opiniones y experiencias con
performance.measureUserAgentSpecificMemory()
Cuéntanos sobre el diseño de la API
¿Existe algún aspecto de la API que no funcione según lo esperado? ¿O hay propiedades faltantes para implementar tu idea? Informa un problema de especificaciones sobre performance.measureUserAgentSpecificMemory() GitHub o agrega tus ideas a un problema existente.
Informar un problema con la implementación
¿Encontraste un error en la implementación de Chrome? ¿O la implementación
diferente de la especificación? Informa un error en new.crbug.com. Asegúrate de
incluye todos los detalles que puedas, brinda instrucciones sencillas para reproducir
el error y establecer los componentes en Blink>PerformanceAPIs
.
Glitch funciona muy bien para compartir repros rápidos y fáciles.
Demostrar apoyo
¿Planeas usar performance.measureUserAgentSpecificMemory()
? Tu apoyo público
ayuda al equipo de Chrome a priorizar funciones y muestra a otros proveedores de navegadores cómo hacerlo
esencial para respaldarlos. Envía un tweet a @ChromiumDev.
y cuéntanos dónde y cómo la utilizas.
Vínculos útiles
- Explicación
- Demostración | Fuente de la demostración
- Seguimiento de errores
- Entrada de ChromeStatus.com
- Cambios desde la API de prueba de origen
- Prueba de origen concluida
Agradecimientos
Muchas gracias a Domenic Denicola, Yoav Weiss y Mathias Bynens por las revisiones de diseño de APIs y Dominik Inführ, Hannes Payer, Kentaro Hara y Michael Lippautz para las revisiones de código en Chrome. También agradezco a Per Parker, Philipp Weis, Olga Belomestnykh, Bolohan y Neil Mckay por proporcionar comentarios valiosos de los usuarios que mejoró la API.