Regresyonları tespit etmek için üretimdeki web sayfanızın bellek kullanımını nasıl ölçeceğinizi öğrenin.
Tarayıcılar, web sayfalarının belleğini otomatik olarak yönetir. Bir web sayfası her nesne oluşturduğunda tarayıcı, nesneyi depolamak için "arka planda" bir bellek parçası ayırır. Bellek sınırlı bir kaynak olduğundan tarayıcı, bir nesnenin artık gerekli olmadığını tespit etmek ve temel bellek parçasını boşaltmak için çöp toplama işlemi gerçekleştirir.
Ancak algılama mükemmel değildir ve Alan Turing'in Durdurma Sorunu, mükemmel algılamanın imkansız bir görev olduğunu kanıtlamıştır. Bu nedenle tarayıcılar, "bir nesneye ihtiyaç duyuluyor" kavramını "bir nesneye erişilebiliyor" kavramıyla yaklaşık olarak ifade eder. Web sayfası, değişkenleri ve diğer erişilebilir nesnelerin alanları aracılığıyla bir nesneye ulaşamıyorsa tarayıcı, nesneyi güvenli bir şekilde geri alabilir. Bu iki kavram arasındaki fark, aşağıdaki örnekte gösterildiği gibi bellek sızıntılarına yol açar.
const object = {a: new Array(1000), b: new Array(2000)};
setInterval(() => console.log(object.a), 1000);
Burada daha büyük dizi b artık gerekli değildir ancak geri çağırmada object.b üzerinden hâlâ erişilebilir olduğundan tarayıcı bunu geri almaz. Bu nedenle, daha büyük dizinin belleği sızdırılır.
Bu çalışmada görüldüğü gibi, bellek sızıntıları web'de yaygındır. Etkinlik işleyicisinin kaydını silmeyi unutarak, bir iframe'den yanlışlıkla nesneler yakalayarak, bir worker sınıfını kapatmayarak, dizilerde nesneler biriktirerek vb. kolayca bellek sızıntısı oluşturabilirsiniz. Bir web sayfasında bellek sızıntısı varsa bellek kullanımı zamanla artar ve web sayfası kullanıcılara yavaş ve şişkin görünür.
Bu sorunu çözmenin ilk adımı, sorunu ölçmektir. Yeni performance.measureUserAgentSpecificMemory() API, geliştiricilerin üretimdeki web sayfalarının bellek kullanımını ölçmesine ve böylece yerel testlerde gözden kaçan bellek sızıntılarını tespit etmesine olanak tanır.
performance.measureUserAgentSpecificMemory() ile eski performance.memory API arasındaki fark nedir?
Mevcut standart olmayan performance.memory API'yi biliyorsanız yeni API'nin bu API'den ne gibi farkları olduğunu merak ediyor olabilirsiniz. Aradaki temel fark, eski API'nin JavaScript yığın boyutunu döndürmesine karşın yeni API'nin web sayfası tarafından kullanılan belleği tahmin etmesidir. Bu fark, Chrome aynı yığını birden fazla web sayfasıyla (veya aynı web sayfasının birden fazla örneğiyle) paylaştığında önemli hale gelir. Bu gibi durumlarda, eski API'nin sonucu rastgele yanlış olabilir. Eski API, "heap" gibi uygulamaya özgü terimlerle tanımlandığından standartlaştırmak mümkün değildir.
Bir diğer fark ise yeni API'nin atık toplama işlemi sırasında bellek ölçümü yapmasıdır. Bu işlem, sonuçlardaki gürültüyü azaltır ancak sonuçların üretilmesi biraz zaman alabilir. Diğer tarayıcıların, yeni API'yi çöp toplama işlemine güvenmeden uygulamaya karar verebileceğini unutmayın.
Önerilen kullanım alanları
Bir web sayfasının bellek kullanımı, etkinliklerin zamanlamasına, kullanıcı işlemlerine ve çöp toplama işlemlerine bağlıdır. Bu nedenle, bellek ölçümü API'si üretimdeki bellek kullanımı verilerini toplamak için tasarlanmıştır. Ayrı ayrı yapılan görüşmelerin sonuçları daha az faydalıdır. Kullanım alanı örnekleri:
- Yeni bellek sızıntılarını yakalamak için web sayfasının yeni bir sürümünün kullanıma sunulması sırasında gerileme tespiti.
- Bellek etkisini değerlendirmek ve bellek sızıntılarını tespit etmek için yeni bir özelliği A/B testine tabi tutma.
- Bellek sızıntılarının olup olmadığını doğrulamak için bellek kullanımını oturum süresiyle ilişkilendirme.
- Bellek kullanımının genel etkisini anlamak için bellek kullanımını kullanıcı metrikleriyle ilişkilendirme.
Tarayıcı uyumluluğu
API şu anda yalnızca Chrome 89'dan itibaren Chromium tabanlı tarayıcılarda desteklenmektedir. Tarayıcılar, nesneleri bellekte farklı şekillerde temsil ettiğinden ve bellek kullanımını farklı şekillerde tahmin ettiğinden API'nin sonucu, uygulamaya büyük ölçüde bağlıdır. Tarayıcılar, uygun muhasebe çok pahalı veya mümkün değilse bazı bellek bölgelerini muhasebeye dahil etmeyebilir. Bu nedenle, sonuçlar tarayıcılar arasında karşılaştırılamaz. Yalnızca aynı tarayıcıya ait sonuçları karşılaştırmak anlamlıdır.
performance.measureUserAgentSpecificMemory() kullanılıyor
Özellik algılama
Yürütme ortamı, çapraz kaynak bilgi sızıntılarını önlemeye yönelik güvenlik şartlarını karşılamıyorsa performance.measureUserAgentSpecificMemory işlevi kullanılamaz veya SecurityError ile başarısız olabilir.
Bu özellik, bir web sayfasının COOP+COEP üstbilgilerini ayarlayarak etkinleştirebileceği çapraz kaynak izolasyonuna dayanır.
Destek, çalışma zamanında algılanabilir:
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);
}
Yerel test
Chrome, bellek ölçümünü atık toplama sırasında gerçekleştirir. Bu nedenle API, sonuç sözünü hemen yerine getirmez ve bunun yerine bir sonraki atık toplama işlemini bekler.
API'yi çağırmak, belirli bir zaman aşımından sonra atık toplama işlemini zorlar. Bu süre şu anda 20 saniye olarak ayarlanmıştır ancak daha kısa sürebilir. Chrome'u --enable-blink-features='ForceEagerMeasureMemory' komut satırı işaretiyle başlatmak, zaman aşımını sıfıra indirir ve yerel hata ayıklama ve test için kullanışlıdır.
Örnek
API'nin önerilen kullanımı, tüm web sayfasının bellek kullanımını örnekleyen ve sonuçları toplama ve analiz için bir sunucuya gönderen genel bir bellek monitörü tanımlamaktır. En basit yöntem, belirli aralıklarla örnekleme yapmaktır. Örneğin, M dakikada bir örnekleme yapabilirsiniz. Ancak bu durum, örnekler arasında bellek zirveleri oluşabileceğinden verilerde önyargıya yol açar.
Aşağıdaki örnekte, örneklerin herhangi bir zamanda eşit olasılıkla gerçekleşmesini sağlayan bir Poisson süreci kullanılarak nasıl tarafsız bellek ölçümleri yapılacağı gösterilmektedir (demo, kaynak).
Öncelikle, setTimeout() ile rastgele aralık kullanarak bir sonraki bellek ölçümünü planlayan bir işlev tanımlayın.
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);
}
measurementInterval() işlevi, ortalama olarak her beş dakikada bir ölçüm olacak şekilde milisaniye cinsinden rastgele bir aralık hesaplar. İşlevin arkasındaki matematiksel işlemlerle ilgileniyorsanız Üstel dağılım başlıklı makaleyi inceleyin.
function measurementInterval() {
const MEAN_INTERVAL_IN_MS = 5 * 60 * 1000;
return -Math.log(Math.random()) * MEAN_INTERVAL_IN_MS;
}
Son olarak, eş zamansız performMeasurement() işlevi API'yi çağırır, sonucu kaydeder ve bir sonraki ölçümü planlar.
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();
}
Son olarak, ölçüme başlayın.
// Start measurements.
scheduleMeasurement();
Sonuç aşağıdaki gibi görünebilir:
// 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']
},
],
}
Toplam bellek kullanımı tahmini, bytes alanında döndürülür. Bu değer, uygulamaya büyük ölçüde bağlıdır ve tarayıcılar arasında karşılaştırılamaz. Hatta aynı tarayıcının farklı sürümleri arasında bile değişebilir. Değer, mevcut süreçteki tüm iFrame'lerin, ilgili pencerelerin ve web çalışanlarının JavaScript ve DOM belleğini içerir.
breakdown listesinde, kullanılan bellek hakkında daha fazla bilgi verilmektedir. Her giriş, belleğin bir kısmını açıklar ve bunu URL ile tanımlanan bir dizi pencere, iframe ve çalışana atfeder. types alanında, bellekle ilişkili uygulamaya özgü bellek türleri listelenir.
Tüm listelere genel bir şekilde yaklaşmak ve belirli bir tarayıcıya dayalı varsayımları sabit kodlamamak önemlidir. Örneğin, bazı tarayıcılar boş bir breakdown veya boş bir attribution döndürebilir. Diğer tarayıcılar, attribution içinde birden fazla giriş döndürerek bu girişlerden hangisinin belleğe sahip olduğunu ayırt edemediklerini belirtebilir.
Geri bildirim
Web Performansı Topluluk Grubu ve Chrome ekibi, performance.measureUserAgentSpecificMemory() ile ilgili düşüncelerinizi ve deneyimlerinizi öğrenmekten memnuniyet duyar.
API tasarımı hakkında bilgi verin
API ile ilgili beklendiği gibi çalışmayan bir durum var mı? Yoksa fikrinizi uygulamak için eksik özellikler mi var? performance.measureUserAgentSpecificMemory() GitHub deposunda bir spesifikasyon sorunu bildirin veya düşüncelerinizi mevcut bir soruna ekleyin.
Uygulamayla ilgili sorun bildirme
Chrome'un uygulamasında bir hata mı buldunuz? Yoksa uygulama, spesifikasyondan farklı mı? new.crbug.com adresinden hata bildirin. Mümkün olduğunca fazla ayrıntı eklediğinizden, hatanın yeniden oluşturulması için basit talimatlar verdiğinizden ve Bileşenler'in Blink>PerformanceAPIs olarak ayarlandığından emin olun.
Desteğinizi gösterme
performance.measureUserAgentSpecificMemory() kullanmayı mı planlıyorsunuz? Herkese açık desteğiniz, Chrome ekibinin özelliklere öncelik vermesine yardımcı olur ve diğer tarayıcı satıcılarına bu özelliklerin desteklenmesinin ne kadar önemli olduğunu gösterir. @ChromiumDev adresine tweet göndererek nerede ve nasıl kullandığınızı bize bildirin.
Faydalı bağlantılar
- Açıklayıcı
- Demo | Demo kaynağı
- İzleme hatası
- ChromeStatus.com girişi
- Kaynak denemesi API'sinden bu yana yapılan değişiklikler
- Tamamlanan deneysel özellik denemesi
Teşekkür
API tasarım incelemeleri için Domenic Denicola, Yoav Weiss ve Mathias Bynens'e, Chrome'daki kod incelemeleri için ise Dominik Inführ, Hannes Payer, Kentaro Hara ve Michael Lippautz'a teşekkür ederiz. Ayrıca, API'yi büyük ölçüde iyileştiren değerli kullanıcı geri bildirimleri sağladıkları için Per Parker, Philipp Weis, Olga Belomestnykh, Matthew Bolohan ve Neil Mckay'e de teşekkür ederim.