Scopri come misurare l'utilizzo della memoria della tua pagina web in produzione per rilevare regressioni.
I browser gestiscono automaticamente la memoria delle pagine web. Ogni volta che una pagina web crea un oggetto, il browser alloca un blocco di memoria "under the hood" a archiviare l'oggetto. Poiché la memoria è una risorsa limitata, il browser esegue garbage collection per rilevare quando un oggetto non è più necessario e liberare il blocco di memoria sottostante.
Il rilevamento non è perfetto però e ha dimostrato che il rilevamento perfetto è un compito impossibile. Pertanto, i browser approssimano la nozione di "un oggetto necessaria". con la nozione di "un oggetto è raggiungibile". Se la pagina web non può raggiungere un oggetto tramite le sue variabili e i campi di altri oggetti raggiungibili, il browser può rivendicare l'oggetto in modo sicuro. La differenza tra questi due concetti portano a perdite di memoria, come illustrato nell'esempio seguente.
const object = {a: new Array(1000), b: new Array(2000)};
setInterval(() => console.log(object.a), 1000);
In questo caso l'array più grande b
non è più necessario, ma il browser non
recuperala perché è ancora raggiungibile tramite object.b
nel callback. Pertanto,
viene divulgata la memoria dell'array più grande.
Le fughe di memoria sono prevalenti sul web. È facile introdurne uno dimenticando di annullare la registrazione di un listener di eventi, acquisire accidentalmente oggetti da un iframe, non chiudendo un worker, accumulando oggetti in array e così via. Se una pagina web presenta perdite di memoria, l'utilizzo della memoria aumenta nel tempo e la pagina web appare lenta e per gli utenti.
Il primo passo per risolvere questo problema è misurarlo. Il nuovo
L'API performance.measureUserAgentSpecificMemory()
consente agli sviluppatori
misurare l'utilizzo della memoria delle proprie pagine web in produzione e rilevare quindi la memoria
perdite che non riescono a superare i test locali.
Qual è la differenza tra performance.measureUserAgentSpecificMemory()
e l'API performance.memory
precedente?
Se hai familiarità con l'API performance.memory
non standard esistente,
forse ti stai chiedendo cosa differenzia la nuova API. La differenza principale è
che la vecchia API restituisce la dimensione dell'heap JavaScript, mentre la nuova API
stima la memoria utilizzata dalla pagina web. Questa differenza diventa
è importante quando Chrome condivide lo stesso heap con più pagine web (o
più istanze della stessa pagina web). In questi casi, il risultato del vecchio
L'API potrebbe essere arbitrariamente disattivata. Poiché la vecchia API è definita
termini specifici dell'implementazione come "heap", la standardizzazione è inutile.
Un'altra differenza è che la nuova API esegue la misurazione della memoria garbage collection. In questo modo si riduce il rumore nei risultati, ma potrebbe essere necessario un finché non vengono generati i risultati. Tieni presente che altri browser potrebbero decidere di di implementare la nuova API senza fare affidamento sulla garbage collection.
Casi d'uso suggeriti
L'utilizzo della memoria di una pagina web dipende dalla tempistica degli eventi, dalle azioni degli utenti e garbage collection. Ecco perché l'API di misurazione della memoria è pensata aggregando i dati sull'utilizzo della memoria dalla produzione. I risultati delle singole chiamate sono meno utili. Esempi di casi d'uso:
- Rilevamento della regressione durante l'implementazione di una nuova versione della pagina web per rilevare nuove perdite di memoria.
- Test A/B di una nuova funzionalità per valutare l'impatto sulla memoria e rilevare le perdite di memoria.
- Correlazione dell'utilizzo della memoria con la durata della sessione per verificare la presenza o l'assenza di perdite di memoria.
- Correlazione dell'utilizzo della memoria con le metriche utente per comprendere l'impatto complessivo della memoria utilizzata.
Compatibilità del browser
Attualmente l'API è supportata solo nei browser basati su Chromium, a partire da Chrome 89. La dipende molto dall'implementazione perché i browser hanno diversi modi di rappresentare gli oggetti in memoria e diversi modi di la stima dell'utilizzo della memoria. I browser possono escludere alcune regioni di memoria da una corretta contabilità se una corretta contabilità è troppo costosa o non fattibile. Di conseguenza, i risultati non possono essere confrontati tra browser. Ha senso solo confrontare per lo stesso browser.
In uso: performance.measureUserAgentSpecificMemory()
Rilevamento delle caratteristiche
La funzione performance.measureUserAgentSpecificMemory
non sarà disponibile o potrebbe
hanno esito negativo con un messaggio SecurityError se l'ambiente di esecuzione non soddisfa
i requisiti di sicurezza per prevenire le fughe di informazioni tra origini.
Si basa sull'isolamento multiorigine, che una pagina web può attivare
impostando le intestazioni COOP+COEP.
Il supporto può essere rilevato in fase di esecuzione:
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);
}
Test locale
Chrome esegue la misurazione della memoria durante la garbage collection, ovvero che l'API non risolva immediatamente la promessa dei risultati, ma attende per la prossima garbage collection.
La chiamata all'API forza una garbage collection dopo un timeout, ovvero
è attualmente impostato su 20 secondi, ma potrebbe avvenire prima. L'avvio di Chrome con
--enable-blink-features='ForceEagerMeasureMemory'
flag della riga di comando riduce
il timeout su zero ed è utile per il debug e i test locali.
Esempio
L'uso consigliato dell'API è definire un monitoraggio della memoria globale che
campiona l'utilizzo della memoria dell'intera pagina web e invia i risultati a un server
per l'aggregazione e l'analisi. Il modo più semplice è eseguire il campionamento periodicamente,
esempio ogni M
minuti. Tuttavia, ciò introduce un bias nei dati perché
tra i campioni potrebbero verificarsi picchi di memoria.
L'esempio seguente mostra come effettuare misurazioni imparziali della memoria utilizzando il processo di Poisson, che garantisce la stessa probabilità che i campioni si verifichino in qualsiasi momento (demo, fonte).
Innanzitutto, definisci una funzione che pianifichi la successiva misurazione della memoria usando
setTimeout()
con un intervallo randomizzato.
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 funzione measurementInterval()
calcola un intervallo casuale in millisecondi
in modo che in media venga eseguita una misurazione ogni cinque minuti. Vedi Esponenziale
distribuzione se ti interessa conoscere i calcoli matematici alla base della funzione.
function measurementInterval() {
const MEAN_INTERVAL_IN_MS = 5 * 60 * 1000;
return -Math.log(Math.random()) * MEAN_INTERVAL_IN_MS;
}
Infine, la funzione performMeasurement()
asincrona richiama l'API, registra
il risultato e pianifica la misurazione successiva.
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();
}
Infine, inizia la misurazione.
// Start measurements.
scheduleMeasurement();
Il risultato potrebbe avere il seguente aspetto:
// 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 stima dell'utilizzo totale della memoria viene restituita nel campo bytes
. Questo valore è
dipende fortemente dall'implementazione e non può essere confrontata tra browser. Potrebbe
passare da una versione all'altra dello stesso browser. Il valore include
Memoria JavaScript e DOM di tutti gli iframe, finestre correlate e web worker in
il processo attuale.
L'elenco breakdown
fornisce ulteriori informazioni sulla memoria utilizzata. Ciascuna
descrive una parte della memoria e la attribuisce a un insieme
finestre, iframe e worker identificati dall'URL. Il campo types
elenca
i tipi di memoria specifici dell'implementazione associati alla memoria.
È importante trattare tutti gli elenchi in modo generico e non applicare una codifica rigida
ipotesi basate su un determinato browser. Ad esempio, alcuni browser
restituisce un valore breakdown
vuoto o un valore attribution
vuoto. Altri browser potrebbero
restituisce più voci in attribution
che indicano che non è possibile distinguere
quale di queste voci possiede la memoria.
Feedback
Il Web Performance Community Group e il team di Chrome vorrebbero
di conoscere le tue opinioni ed esperienze con
performance.measureUserAgentSpecificMemory()
.
Parlaci della progettazione dell'API
C'è qualcosa che non funziona come previsto nell'API? Oppure ci sono mancano delle proprietà necessarie per implementare la tua idea? Segnala un problema con le specifiche il repository GitHub performance.measureUserAgentSpecificMemory() o aggiungi le tue opinioni su un problema esistente.
Segnalare un problema con l'implementazione
Hai trovato un bug nell'implementazione di Chrome? Oppure l'implementazione
rispetto alle specifiche? Segnala un bug all'indirizzo new.crbug.com. Assicurati di
includere il maggior numero di dettagli possibile, fornire semplici istruzioni per la riproduzione
il bug e impostare Componenti su Blink>PerformanceAPIs
.
Glitch è la soluzione perfetta per condividere riproduzioni in modo facile e veloce.
Mostra il tuo sostegno
Hai intenzione di utilizzare performance.measureUserAgentSpecificMemory()
? Il tuo supporto pubblico
aiuta il team di Chrome a dare la priorità alle funzionalità e mostra ad altri fornitori di browser come
è fondamentale supportarli. Invia un tweet a @ChromiumDev
e facci sapere dove e come lo utilizzi.
Link utili
- Spiegazione
- Demo | Fonte della demo
- Monitoraggio del bug
- Voce ChromeStatus.com
- Modifiche rispetto all'API Origin Trial
- Prova dell'origine conclusa
Ringraziamenti
Ringraziamo Domenic Denicola, Yoav Weiss e Mathias Bynens per le recensioni sulla progettazione delle API. e Dominik Inführ, Hannes Payer, Kentaro Hara, Michael Lippautz per le revisioni del codice. in Chrome. Ringrazio anche Per Parker, Philipp Weis, Olga Belomestnykh, Matthew Bolohan e Neil Mckay per aver fornito un prezioso feedback agli utenti che ha notevolmente ha migliorato l'API.