Skip to main content

Aprenda a medir el uso de memoria de su p谩gina web en producci贸n para detectar regresiones.

Los navegadores gestionan la memoria de las p谩ginas web de forma autom谩tica. Siempre y cuando una p谩gina web crea un objeto, el navegador asigna una parte de la memoria 芦debajo del cap贸禄 para guardar el objeto. Ya que la memoria es un recurso finito, el navegador realiza una recolecci贸n de basura para detectar cuando un objeto ya no hace falta y para liberar el bloque de memoria subyacente. A pesar de todo, la detecci贸n no es perfecta y
fue probado que la detecci贸n perfecta es una tarea imposible. Por ende, los navegadores aproximan la noci贸n de 芦un objeto hace falta禄 con la noci贸n de 芦un objeto es alcanzable禄. Si la p谩gina web no puede llegar a un objeto a trav茅s de sus variables y los campos de otros objetos accesibles, entonces el navegador puede recuperar el objeto de forma segura. La diferencia entre estas dos nociones conduce a p茅rdidas 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铆 la matriz m谩s grande b ya no hace falta, pero el navegador no lo recupera debido a que a煤n es alcanzable a trav茅s de object.b en la devoluci贸n de llamada. Por ende, se filtra la memoria de la matriz m谩s grande.

Las fugas de memoria son prevalente en la Web. Es f谩cil introducir uno olvid谩ndose de anular el registro de un detector de eventos, capturando accidentalmente objetos de un iframe, no cerrando un empleado, acumulando objetos en matrices, etc. Si una p谩gina web tiene p茅rdidas de memoria, su uso de memoria aumenta con el tiempo y la p谩gina web parece lenta e hinchada para los usuarios.

El primer paso para solucionar este problema es medirlo. El nuevo
performance.measureMemory() API posibilita a los desarrolladores medir el uso de memoria de sus p谩ginas web en producci贸n y as铆 detectar p茅rdidas de memoria que se escapan a trav茅s de pruebas locales.

Como es performance.measureMemory() distinto al legado performance.memory API?

Si est谩 familiarizado con el no est谩ndar existente performance.memory API, es factible que se pregunte 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 nueva API estima el uso de memoria de toda la p谩gina web. Esta diferencia se torna 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 antigua API puede estar arbitrariamente apagado. Ya que la antigua API se establece en t茅rminos espec铆ficos de implementaci贸n como 芦mont贸n禄, estandarizarla es in煤til.

Otra diferencia es que la nueva API realiza mediciones de memoria durante la recolecci贸n de basura. Esto reduce el ruido en los resultados, pero puede llevar un tiempo hasta que se produzcan los resultados. Tenga en cuenta que otros navegadores pueden elegir poner en pr谩ctica la nueva API sin depender de la recolecci贸n de basura.

Casos de uso sugeridos

El uso de memoria de una p谩gina web depende del momento de los eventos, las acciones del usuario y las recolecciones de basura. Es es por esto que que la API de medici贸n de memoria est谩 dise帽ada para agregar datos de uso de memoria de producci贸n. Los resultados de las llamadas individuales son menos 煤tiles. Casos de uso 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.
  • Prueba A / B de una nueva funci贸n para examinar su impacto en la memoria y detectar p茅rdidas de memoria.
  • Correlacionar el uso de la memoria con la duraci贸n de la sesi贸n para verificar la presencia o ausencia de p茅rdidas de memoria.
  • Correlacionar el uso de la memoria con las m茅tricas del usuario para entender el impacto general del uso de la memoria.

Compatibilidad del navegador

En este momento, la API solo es compatible con Chrome 83 como prueba de origen. El resultado de la API depende en gran medida de la implementaci贸n debido a que los navegadores disponen diferentes formas de representar objetos en la memoria y diferentes formas de estimar el uso de la memoria. Los navegadores pueden excluir algunas regiones de memoria de la contabilidad si la contabilidad adecuada es demasiado cara o inviable. Por ende, los resultados no se pueden comparar entre navegadores. Solo tiene sentido comparar los resultados para el mismo navegador.

Estado actual

Paso Estado
1. Crea un explicador Completar
2. Crear borrador inicial de especificaci贸n En progreso
3. Recopile comentarios y repita el dise帽o En progreso
4. Prueba de origen En progreso
5. Lanzamiento No empezado

Usando performance.measureMemory()

Habilitar el apoyo durante la etapa de prueba de origen

los performance.measureMemory() La API se encuentra disponible como prueba de origen a partir de Chrome 83. Se espera que la prueba de origen finalice en Chrome 86 a principios de noviembre de 2020.

Las pruebas de Origin le posibilitan probar nuevas funciones y otorgar comentarios sobre su usabilidad, practicidad y efectividad a la comunidad de est谩ndares web. Para conseguir m谩s informaci贸n, consulte el Gu铆a de pruebas de Origin para desarrolladores web. Para inscribirse en esta u otra prueba de origen, visite el p谩gina de registro.

Reg铆strese para la prueba de origen

  1. Solicita un token por tu origen.
  2. Agrega el token a tus p谩ginas. Hay dos maneras de hacerlo:
    • Agregar un origin-trial <meta> etiqueta al encabezado de cada p谩gina. A modo de ejemplo, esto puede verse as铆:
      <meta http-equiv="origin-trial" content="TOKEN_GOES_HERE">
    • Si puede configurar su servidor, adem谩s puede agregar el token utilizando un Origin-Trial Encabezado HTTP. El encabezado de respuesta resultante deber铆a verse as铆:
      Origin-Trial: TOKEN_GOES_HERE

Habilitaci贸n a trav茅s de chrome: // flags

Para experimentar con performance.measureMemory() sin un token de prueba de origen, habilite el #experimental-web-platform-features bandera en chrome://flags.

Detecci贸n de caracter铆sticas

los performance.measureMemory() la funci贸n puede fallar con un
Error de seguridad si el entorno de ejecuci贸n no alcanza con los requerimientos de seguridad para prevenir fugas de informaci贸n de origen cruzado. Durante la prueba de origen en Chrome, la API necesita que Aislamiento del sitio est谩 habilitado. Cuando se env铆e la API, depender谩 de
aislamiento de origen cruzado. Una p谩gina web puede elegir por el aislamiento de origen cruzado configurando Encabezados COOP + COEP.

if (performance.measureMemory) {
let result;
try {
result = await performance.measureMemory();
} 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 basura. Esto significa que la API no resuelve la promesa de resultado de inmediato y, en cambio, espera la pr贸xima recolecci贸n de basura. La API fuerza una recolecci贸n de basura luego de un tiempo de espera, que en este momento est谩 establecido en 20 segundos. Iniciando Chrome con el
--enable-blink-features='ForceEagerMeasureMemory' El indicador de l铆nea de comandos reduce el tiempo de espera a cero y es 煤til para la depuraci贸n y las pruebas locales.

Ejemplo

El uso recomendado de la API es establecer un monitor de memoria global que muestree el uso de memoria de toda la p谩gina web y env铆e los resultados a un servidor para su agregaci贸n y an谩lisis. La forma m谩s sencilla es tomar muestras de forma peri贸dica, a modo de ejemplo, cada M minutos. A pesar de todo, esto introduce un sesgo en los datos debido a que pueden producirse picos de memoria entre las muestras. El siguiente ejemplo muestra c贸mo realizar mediciones de memoria insesgadas usando un Procedimiento de Poisson, lo que garantiza que las muestras tengan la misma probabilidad de ocurrir en cualquier momento (manifestaci贸n, fuente).

Primero, defina una funci贸n que programe la pr贸xima medici贸n de memoria utilizando
setTimeout() con un intervalo aleatorio. La funci贸n debe llamarse luego de cargar la p谩gina en la ventana principal.

function scheduleMeasurement() {
if (!performance.measureMemory) {
console.log("performance.measureMemory() is not available.");
return;
}
const interval = measurementInterval();
console.log("Scheduling memory measurement in " +
Math.round(interval / 1000) + " seconds.");
setTimeout(performMeasurement, interval);
}


window.onload = function () {
scheduleMeasurement();
}

los measurementInterval() La funci贸n calcula un intervalo aleatorio en milisegundos de modo que, en promedio, hay una medici贸n cada cinco minutos. Ver Distribuci贸n exponencial si est谩 interesado en las matem谩ticas 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;
}

En resumen, el async performMeasurement() La funci贸n invoca la API, registra el resultado y programa la pr贸xima medici贸n.

async function performMeasurement() {
let result;
try {
result = await performance.measureMemory();
} catch (error) {
if (error instanceof DOMException &&
error.name === "SecurityError") {
console.log("The context is not secure.");
return;
}
throw error;
}
console.log("Memory usage:", result);
scheduleMeasurement();
}

El resultado puede verse como sigue:


{
bytes: 60_000_000,
breakdown: [
{
bytes: 40_000_000,
attribution: ["https://foo.com"],
userAgentSpecificTypes: ["Window", "JS"]
},
{
bytes: 20_000_000,
attribution: ["https://foo.com/iframe"],
userAgentSpecificTypes: ["Window", "JS"]
}
]
}

La estimaci贸n del uso total de memoria se devuelve en el bytes campo. El valor de bytes est谩 utilizando sintaxis del separador num茅rico. Este valor depende en gran medida de la implementaci贸n y no se puede comparar entre navegadores. Inclusive puede cambiar entre diferentes versiones del mismo navegador. Durante la prueba de origen, el valor incluye el uso de memoria JavaScript de la ventana principal y todos
mismo sitio iframes y ventanas asociadas. Cuando se env铆a la API, el valor tendr谩 en cuenta JavaScript y la memoria DOM de todos los iframes, ventanas asociadas y empleados web.

los breakdown El listado proporciona m谩s informaci贸n sobre la memoria utilizada. Cada entrada describe una parte de la memoria y la atribuye a un recopilatorio de ventanas, iframes y empleados identificados por URL. los userAgentSpecificTypes
El campo enumera los tipos de memoria espec铆ficos de la implementaci贸n asociados con la memoria.

Es esencial tratar todas las listas de forma gen茅rica y no codificar suposiciones sustentadas en un navegador en particular. A modo de ejemplo, algunos navegadores pueden devolver un breakdown o un vacio attribution. Otros navegadores pueden devolver varias URL en attribution lo que indica que no pudieron distinguir cu谩l de estas URL es propietaria de la memoria.

Realimentaci贸n

los Grupo comunitario de rendimiento web y al equipo de Chrome le encantar铆a conocer sus opiniones y experiencias con
performance.measureMemory().

Cu茅ntanos sobre el dise帽o de la API

驴Puede haber algo en la API que no funcione como se esperaba? 驴O faltan propiedades que necesitas para poner en pr谩ctica tu idea? Presentar un obst谩culo de especificaciones en el performance.measureMemory Repositorio de GitHub o agregue sus pensamientos a un obst谩culo existente.

Informar un obst谩culo con la implementaci贸n

驴Encontraste un error con la implementaci贸n de Chrome? 驴O la implementaci贸n es distinto de la especificaci贸n? Presentar un error en new.crbug.com. Aseg煤rese de incluir todos los detalles que pueda, proporcione instrucciones sencillas para reproducir el error y Componentes ajustado a Blink>PerformanceAPIs.
Falla funciona muy bien para compartir repros r谩pidos y f谩ciles.

Mostrar apoyo

驴Est谩 planeando utilizar performance.measureMemory()? Su apoyo p煤blico ayuda al equipo de Chrome a priorizar funciones y muestra a otros proveedores de navegadores lo importante que es brindarles soporte. Enviar un tweet a @Cromodev y h谩ganos saber d贸nde y c贸mo lo est谩 utilizando.

Links 脷tiles

Agradecimientos

Muchas gracias a Domenic Denicola, Yoav Weiss, Mathias Bynens por las revisiones de dise帽o de API y a Dominik Inf眉hr, Hannes Payer, Kentaro Hara, Michael Lippautz por las revisiones de c贸digo en Chrome. Adem谩s agradezco a Per Parker, Philipp Weis, Olga Belomestnykh, Matthew Bolohan y Neil Mckay por otorgar valiosos comentarios de los usuarios que mejoraron enormemente la API.

Imagen de h茅roe por Harrison Broadbent en Unsplash