Découvrez comment mesurer l'utilisation de la mémoire de votre page Web en production pour détecter les régressions.
Les navigateurs gèrent automatiquement la mémoire des pages Web. Chaque fois qu'une page Web crée un objet, le navigateur alloue un fragment de mémoire "sous le capot" à stocker l'objet. La mémoire étant une ressource finie, le navigateur effectue une récupération de mémoire pour détecter quand un objet n'est plus nécessaire et pour libérer le fragment de mémoire sous-jacent.
La détection n'est cependant pas parfaite et elle a prouvé que la détection parfaite est une tâche impossible. Par conséquent, les navigateurs se rapprochent de la notion d'objet est nécessaire." avec la notion "un objet est accessible". Si la page Web ne peut pas atteindre un objet via ses variables et les champs d'autres objets accessibles, alors le navigateur peut récupérer l'objet en toute sécurité. La différence entre ces deux notions entraînent des fuites de mémoire, comme illustré dans l'exemple suivant.
const object = {a: new Array(1000), b: new Array(2000)};
setInterval(() => console.log(object.a), 1000);
Ici, le plus grand tableau b
n'est plus nécessaire, mais le navigateur n'a pas besoin
le récupérer, car il est toujours joignable via object.b
dans le rappel. Ainsi,
la mémoire du plus grand tableau est divulguée.
Les fuites de mémoire sont préoccupées sur le Web. Il est facile d'en introduire un en oubliant d'annuler l'enregistrement d'un écouteur d'événements. capturer accidentellement des objets à partir d'un iFrame, en ne fermant pas un worker, l'accumulation d'objets dans des tableaux, etc. Si une page Web présente des fuites de mémoire, son utilisation de la mémoire augmente au fil du temps et la page Web semble lente et gonflée aux utilisateurs.
La première étape pour résoudre ce problème consiste à le mesurer. Les nouvelles
L'API performance.measureUserAgentSpecificMemory()
permet aux développeurs de
de mesurer l'utilisation de la mémoire par leurs pages Web en production et de détecter ainsi la mémoire
qui passent par les tests locaux.
En quoi performance.measureUserAgentSpecificMemory()
est-il différent de l'ancienne API performance.memory
?
Si vous connaissez l'API performance.memory
non standard existante,
vous vous demandez peut-être en quoi
la nouvelle API diffère de celle-ci. La principale différence est
que l'ancienne API renvoie la taille du tas de mémoire JavaScript, tandis que la nouvelle API
estime la mémoire utilisée par la page Web. Cette différence devient
important lorsque Chrome partage le même tas de mémoire avec plusieurs pages Web (ou
plusieurs instances d'une même page Web). Dans ce cas, le résultat de l'ancienne requête
API peut être arbitrairement désactivée. Puisque l'ancienne API est définie
des termes propres à l'implémentation, tels que "tas de mémoire",
et la normalisation n'a aucun espoir.
Autre différence : la nouvelle API mesure la mémoire la récupération de mémoire. Cela réduit le bruit dans les résultats, mais peut jusqu'à ce que les résultats soient produits. Notez que d'autres navigateurs peuvent décider de implémenter la nouvelle API sans utiliser la récupération de mémoire.
Cas d'utilisation suggérés
L'utilisation de la mémoire d'une page Web dépend de la durée des événements, des actions de l'utilisateur et des récupérations de mémoire. C'est pourquoi l'API de mesure de la mémoire est destinée en agrégeant les données d'utilisation de mémoire à partir de la production. Résultats d'appels individuels sont moins utiles. Exemples de cas d'utilisation :
- Détection de régressions lors du déploiement d'une nouvelle version de la page Web pour détecter les nouvelles fuites de mémoire.
- Effectuer des tests A/B sur une nouvelle fonctionnalité pour évaluer son impact sur la mémoire et détecter les fuites de mémoire
- Corrélation de l'utilisation de la mémoire avec la durée de la session pour vérifier la présence ou l'absence de fuites de mémoire.
- Mettre en corrélation l'utilisation de la mémoire avec les métriques utilisateur pour comprendre l'impact global de l'utilisation de la mémoire.
Compatibilité du navigateur
Navigateurs pris en charge
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
Actuellement, l'API n'est compatible qu'avec les navigateurs basés sur Chromium, à partir de Chrome 89. La du résultat de l'API est fortement tributaire de l'implémentation, car les navigateurs ont différentes manières de représenter des objets en mémoire et différentes manières pour estimer l'utilisation de la mémoire. Il est possible que les navigateurs excluent certaines régions de mémoire des la traçabilité si une bonne traçabilité est trop coûteuse ou impossible à réaliser. Ainsi, les résultats ne peuvent pas être comparées entre les navigateurs. Il n'est intéressant que de comparer pour le même navigateur.
performance.measureUserAgentSpecificMemory()
utilisé(s)
Détection de caractéristiques
La fonction performance.measureUserAgentSpecificMemory
ne sera pas disponible ou pourra
échouent avec une erreur SecurityError si l'environnement d'exécution ne répond pas
les exigences de sécurité pour empêcher
les fuites d'informations d'origine croisée.
Il repose sur l'isolation multi-origine qu'une page Web peut activer.
en définissant des en-têtes COOP+COEP.
La prise en charge peut être détectée au moment de l'exécution:
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 local
Chrome effectue la mesure de la mémoire lors de la récupération de mémoire, ce qui signifie que l'API ne résout pas immédiatement la promesse de résultat et attend plutôt pour la prochaine récupération de mémoire.
L'appel de l'API force une récupération de mémoire après un certain délai, ce qui est
actuellement défini sur 20 secondes, mais cela peut arriver plus tôt. Lancer Chrome avec le
L'option de ligne de commande --enable-blink-features='ForceEagerMeasureMemory'
réduit
le délai avant expiration sur zéro et
est utile pour le débogage et les tests locaux.
Exemple
L'utilisation recommandée de l'API consiste à définir un moniteur de mémoire globale
échantillonne l'utilisation de la mémoire de l'ensemble de la page Web et envoie les résultats à un serveur
pour l'agrégation et l'analyse. Le moyen le plus simple consiste à effectuer un échantillonnage régulier, pour
par exemple toutes les M
minutes. Cependant, cela introduit un biais
dans les données, car
des pics de mémoire peuvent
se produire entre les échantillons.
L'exemple suivant montre comment mesurer la mémoire de façon impartiale à l'aide d'un processus de Poisson, qui garantit que les échantillons ont la même probabilité de se produire à tout moment (démonstration, source).
Tout d'abord, définissez une fonction qui planifie la prochaine mesure de la mémoire à l'aide de
setTimeout()
avec un intervalle aléatoire.
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 fonction measurementInterval()
calcule un intervalle aléatoire en millisecondes.
de sorte qu'il y ait en moyenne
une mesure toutes les cinq minutes. Voir la section Exponentielle
distribution si vous vous intéressez aux mathématiques qui se cachent derrière la fonction.
function measurementInterval() {
const MEAN_INTERVAL_IN_MS = 5 * 60 * 1000;
return -Math.log(Math.random()) * MEAN_INTERVAL_IN_MS;
}
Enfin, la fonction asynchrone performMeasurement()
appelle l'API, enregistre
le résultat et planifie la mesure suivante.
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();
}
Enfin, commencez à mesurer.
// Start measurements.
scheduleMeasurement();
Le résultat peut ressembler à ce qui suit:
// 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']
},
],
}
L'estimation de l'utilisation totale de la mémoire est renvoyée dans le champ bytes
. Cette valeur est
dépend fortement de l'implémentation et ne peut pas être comparée d'un navigateur à l'autre. Il peut
même de passer d'une version à l'autre du même navigateur. Cette valeur inclut
Mémoire JavaScript et DOM de tous les iFrames, fenêtres associées et nœuds de calcul Web dans
le processus actuel.
La liste breakdown
fournit des informations supplémentaires sur la mémoire utilisée. Chaque
décrit une partie de la mémoire et l'attribue à un ensemble
les fenêtres, les iFrames et les workers
identifiés par une URL. Le champ types
indique
les types de mémoire spécifiques à l'implémentation associés à la mémoire.
Il est important de traiter toutes les listes de manière générique et de ne pas les coder en dur.
sur la base d'un navigateur particulier. Par exemple, certains navigateurs peuvent
renvoient un breakdown
vide ou un attribution
vide. D'autres navigateurs peuvent
renvoie plusieurs entrées dans attribution
, ce qui indique qu'elles n'ont pas pu faire la distinction
à laquelle de ces entrées appartient la mémoire.
Commentaires
Le groupe de la communauté Web Performance et l'équipe Chrome seront ravis
pour connaître votre avis et vos expériences concernant
performance.measureUserAgentSpecificMemory()
Présentez-nous la conception de l'API
Y a-t-il un aspect de l'API qui ne fonctionne pas comme prévu ? Ou y a-t-il les propriétés dont vous avez besoin pour mettre en œuvre votre idée ? Signaler un problème de spécification sur le dépôt GitHub performance.measureUserAgentSpecificMemory() ou ajoutez vos réflexions sur un problème existant.
Signaler un problème d'implémentation
Avez-vous détecté un bug dans l'implémentation de Chrome ? Ou l'implémentation
différent des spécifications ? Signalez un bug sur new.crbug.com. N'oubliez pas
incluez autant de détails que possible, fournissez des instructions simples pour reproduire
le bug et définissez l'option Composants sur Blink>PerformanceAPIs
.
Glitch est idéal pour partager des répétitions rapidement et facilement.
Montrez votre soutien
Prévoyez-vous d'utiliser performance.measureUserAgentSpecificMemory()
? Votre soutien public
aide l'équipe Chrome à hiérarchiser les fonctionnalités et montre aux autres fournisseurs de navigateurs comment
il est essentiel
de les soutenir. Envoyez un tweet à @ChromiumDev.
et n'hésitez pas à nous dire où et comment vous l'utilisez.
Liens utiles
- Vidéo explicative
- Démonstration | Source de la démonstration
- Bug de suivi
- Entrée ChromeStatus.com
- Modifications apportées depuis l'API Origin Trial
- Phase d'évaluation terminée
Remerciements
Un grand merci à Domenic Denicola, Yoav Weiss, Mathias Bynens pour leurs revues sur la conception d'API, Dominik Inführ, Hannes Payer, Kentaro Hara et Michael Lippautz pour des revues de code dans Chrome. Je remercie aussi Per Parker, Philipp Weis, Olga Belomestnykh, Matthew. Bolohan et Neil Mckay pour les précieux commentaires des utilisateurs qui ont grandement amélioré l'API.