Regresyonları tespit etmek için üretimde 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ı nesne oluşturduğunda, tarayıcı nesneyi depolamak için "gelişmiş" bir bellek parçasını ayırır. Bellek sınırlı bir kaynak olduğundan tarayıcı, bir nesnenin artık gerekli olmadığını algılamak 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 mükemmel algılamanın imkansız olduğu kanıtlanmıştır. Bu nedenle tarayıcılar, "nesne gerekiyor" kavramını "nesne erişilebilir" kavramıyla tahmin eder. Web sayfası, değişkenleri ve erişilebilir diğer nesnelerin alanları aracılığıyla bir nesneye ulaşamazsa 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 b
dizisine artık ihtiyaç yoktur ancak tarayıcı, geri çağırma işlevinde object.b
aracılığıyla hâlâ erişilebildiği için diziyi yeniden talep etmez. Bu nedenle, daha büyük dizinin belleği sızar.
Bellek sızıntısı web'de yaygındır. Etkinlik işleyicinin kaydını silmeyi unutarak, iframe'den nesneleri yanlışlıkla yakalama, bir çalışanı kapatmama, nesneleri dizilerde biriktirme gibi yöntemleri kullanarak basit bir tanımlama yapmak kolaydır. Bir web sayfasında bellek sızıntısı varsa bellek kullanımı zaman içinde artar ve web sayfası kullanıcılara yavaş ve hantal görünür.
Bu sorunu çözmenin ilk adımı problemi ölçmektir. Yeni performance.measureUserAgentSpecificMemory()
API, geliştiricilerin üretimdeki web sayfalarının bellek kullanımını ölçmesine ve böylece yerel testte gözden kaçan bellek sızıntılarını tespit etmesine olanak tanır.
performance.measureUserAgentSpecificMemory()
ile eski performance.memory
API'si arasındaki fark nedir?
Mevcut standart olmayan performance.memory
API hakkında bilginiz varsa yeni API'nin ondan farkını merak ediyor olabilirsiniz. İki API arasındaki temel fark, eski API'nin JavaScript yığınının boyutunu döndürmesi, yeni API'nin ise web sayfası tarafından kullanılan belleği tahmin etmesidir. Chrome aynı yığını birden fazla web sayfasıyla (veya aynı web sayfasının birden fazla örneğiyle) paylaştığında bu fark önemli hale gelir. Bu gibi durumlarda, eski API'nin sonucu keyfi olarak yanlış olabilir. Eski API, "heap" gibi uygulamaya özgü terimlerle tanımlandığından standartlaştırılması umutsuzdur.
Bir diğer fark ise yeni API'nin, çöp toplama sırasında bellek ölçümü yapmasıdır. Bu işlem, sonuçlardaki gürültüyü azaltır ancak sonuçların oluşturulması biraz zaman alabilir. Diğer tarayıcıların, yeni API'yi çöp toplama işlemine başvurmadan uygulamaya karar verebileceğini unutmayın.
Önerilen kullanım alanları
Web sayfalarının bellek kullanımı; etkinliklerin zamanlamasına, kullanıcı işlemlerine ve atık 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. Tekil aramaların sonuçları daha az kullanışlı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 algılama.
- Bellek üzerindeki etkisini değerlendirmek ve bellek sızıntılarını tespit etmek için yeni bir özelliği A/B testi ile test etme.
- Bellek sızıntısı 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 ve sonraki sürümlerde Chromium tabanlı tarayıcılarda desteklenmektedir. Tarayıcıların bellekteki nesneleri temsil etme ve bellek kullanımını tahmin etme yöntemleri farklı olduğundan API'nin sonucu büyük ölçüde uygulamaya bağlıdır. Doğru muhasebe çok pahalı veya uygulanabilir değilse tarayıcılar bazı bellek bölgelerini muhasebeden hariç tutabilir. 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ı, kaynaklar arası bilgi sızıntılarını önlemeye yönelik güvenlik gereksinimlerini karşılamıyorsa performance.measureUserAgentSpecificMemory
işlevi kullanılamaz veya SecurityError hatasıyla başarısız olabilir.
Bu özellik, bir web sayfasının COOP+COEP üstbilgilerini ayarlayarak etkinleştirebileceği çapraz kaynak izolasyonunu kullanı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, atık toplama sırasında bellek ölçümünü gerçekleştirir. Bu, API'nin vadedileni hemen çözümlemediği ve bunun yerine bir sonraki atık toplama işlemini beklediği anlamına gelir.
API'nin çağrılması, bir miktar zaman aşımından sonra atık toplamayı zorlar. Bu süre şu anda 20 saniyeye ayarlanmıştır ancak daha erken gerçekleşebilir. 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 yararlıdır.
Örnek
API'nin önerilen kullanımı, web sayfasının tamamının bellek kullanımını örnekleyen ve sonuçları toplama ve analiz için bir sunucuya gönderen global bir bellek izleyici tanımlamaktır. En basit yöntem, örneğin M
dakikada bir düzenli olarak örnekleme yapmaktır. Ancak bu, örnekler arasında bellek zirveleri oluşabileceğinden verilere önyargı getirir.
Aşağıdaki örnekte, Poisson süreci kullanılarak tarafsız bellek ölçümlerinin nasıl yapılacağı gösterilmektedir. Bu süreç, örneklerin herhangi bir zamanda eşit olasılıkla gerçekleşmesini garanti eder (demo, source).
Öncelikle, rastgele aralıklarla setTimeout()
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 beş dakikada bir ölçüm olacak şekilde milisaniye cinsinden rastgele bir aralık hesaplar. İşlevin arkasındaki matematikle ilgileniyorsanız Üstel dağılım bölümüne bakın.
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 çok bağlıdır ve tarayıcılar arasında karşılaştırılamaz. Aynı tarayıcının farklı sürümleri arasında bile değişiklik yapabilir. Değer, mevcut işlemdeki tüm iFrame'lerin, ilgili pencerelerin ve web çalışanlarının JavaScript ve DOM belleğini içerir.
breakdown
listesi, kullanılan bellek hakkında daha fazla bilgi sağlar. Her giriş, belleğin bir kısmını tanımlar ve bu kısmı URL ile tanımlanan bir dizi pencere, iframe ve çalışana bağlar. types
alanında, bellekle ilişkili uygulamaya özgü bellek türleri listelenir.
Tüm listeleri genel bir şekilde ele almak ve belirli bir tarayıcıya dayalı varsayımları koda sabitlememek önemlidir. Örneğin, bazı tarayıcılar boş bir breakdown
veya boş bir attribution
döndürebilir. Diğer tarayıcılar, attribution
alanında belleğin sahibini ayırt edemediklerini belirten birden fazla giriş döndürebilir.
Geri bildirim
Web Performansı Topluluğu 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 şey var mı? Yoksa fikrinizi uygulamak için ihtiyaç duyduğunuz özellikler eksik mi? performance.measureUserAgentSpecificMemory() GitHub deposunda spesifikasyon sorunu bildirin veya mevcut bir soruna düşüncelerinizi ekleyin.
Uygulamayla ilgili sorunları bildirme
Chrome'un uygulamasında bir hata mı buldunuz? Yoksa uygulama, spesifikasyondan farklı mı? new.crbug.com adresinde hata bildiriminde bulunun. Mümkün olduğunca çok ayrıntı eklediğinizden, hatayı yeniden oluşturmak için basit talimatlar sağladığınızdan ve Bileşenler'i Blink>PerformanceAPIs
olarak ayarladığınızdan emin olun.
Glitch, hızlı ve kolay yeniden oluşturma işlemlerini paylaşmak için idealdir.
Destek gösterme
performance.measureUserAgentSpecificMemory()
'ü kullanmayı planlıyor musunuz? Herkese açık desteğiniz, Chrome ekibinin özelliklere öncelik vermesine yardımcı olur ve diğer tarayıcı tedarikçi firmalarına bu özellikleri desteklemenin ne kadar önemli olduğunu gösterir. @ChromiumDev hesabına tweet göndererek bu özelliği nerede ve nasıl kullandığınızı bize bildirin.
Faydalı bağlantılar
- Açıklayıcı
- Demo | Demo kaynağı
- Hata izleme
- ChromeStatus.com girişi
- Origin Trial API'den bu yana yapılan değişiklikler
- Origin denemesi sona erdi
Teşekkür ederiz
API tasarımı incelemeleri için Domenic Denicola, Yoav Weiss, Mathias Bynens ve Chrome'daki kod incelemeleri için Dominik Inführ, Hannes Payer, Kentaro Hara, Michael Lippautz'a çok teşekkür ederiz. 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 Bolahan ve Neil Mckay'a da teşekkür ederiz.
Unsplash'tan Harrison Broadbent tarafından oluşturulan lokomotif resim