Web sayfanızın toplam bellek kullanımını measurementUserAgentspecificMemory() ile izleyin

Regresyonları tespit etmek için web sayfanızın üretimde bellek kullanımını nasıl ölçeceğinizi öğrenin.

Burçin Bilgili
Brendan Kenny
Ulan Degenbaev
Ulan Degenbaev

Tarayıcılar, web sayfalarının belleğini otomatik olarak yönetir. Bir web sayfası bir nesne oluşturduğunda tarayıcı, nesneyi depolamak için "gelişmiş seçenekler"e sahip bir bellek parçası ayırır. Bellek sınırlı bir kaynak olduğundan tarayıcı, artık bir nesneye ihtiyaç duyulmadığında bunu algılamak ve alttaki bellek parçasını serbest bırakmak için atık toplama işlemi gerçekleştirir.

Yine de algılama mükemmel değildir ve mükemmel tespitin imkansız bir iş olduğu kanıtlandı. Bu nedenle tarayıcılar, "bir nesne gerekli" kavramını, "bir nesne erişilebilir" kavramıyla yaklaşır. Web sayfası, değişkenleri ve erişilebilir diğer nesnelerin alanları aracılığıyla bir nesneye erişemezse 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 olan b dizisine artık ihtiyaç duyulmamaktadır, ancak geri çağırmada object.b aracılığıyla hâlâ erişilebildiği için tarayıcı bu diziyi geri talep etmez. Böylece, daha büyük olan dizinin belleği sızdırılır.

Bellek sızıntıları web'de yaygın bir şekilde görülür. Etkinlik işleyici kaydını iptal etmeyi unutarak, nesneleri yanlışlıkla bir iframe'den yakalayarak, bir çalışanı kapatmayarak, dizilerde nesneleri toplayarak ve benzer işlemler yaparak kolayca kullanılabilir hale getirebilirsiniz. Bir web sayfasında bellek sızıntısı varsa bellek kullanımı zamanla artar ve web sayfası kullanıcılara yavaş ve şişmiş görünür.

Bu sorunu çözmenin ilk adımı sorunu ölçmektir. Yeni performance.measureUserAgentSpecificMemory() API, geliştiricilerin üretimde web sayfalarının bellek kullanımını ölçmesine ve böylece yerel testlerden 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 hakkında bilginiz varsa yeni API'nin ondan farkını merak ediyor olabilirsiniz. Aralarındaki temel fark, eski API'nin JavaScript yığınının boyutunu döndürmesi, yeni API ise web sayfası tarafından kullanılan belleğin tahmin edilmesidir. 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 rastgele şekilde devre dışı bırakılabilir. Eski API, "yığın" gibi uygulamaya özgü terimlerle tanımlandığı için standart hale getirilmesi umutsuz bir işlemdir.

Diğer bir fark da yeni API'nin atık toplama sırasında bellek ölçümü yapmasıdır. Bu, sonuçlardaki gürültüyü azaltır ancak sonuçların üretilmesi biraz zaman alabilir. Diğer tarayıcıların, çöp toplama işlemine gerek kalmadan yeni API'yi 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 atık koleksiyonlarına bağlıdır. Bu nedenle bellek ölçüm API'si, üretimden bellek kullanımı verilerini toplamak üzere tasarlanmıştır. Tek tek aramaların 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 regresyon algılaması.
  • Bellek etkisini değerlendirmek ve bellek sızıntılarını tespit etmek için yeni bir özelliğin A/B testi.
  • 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

Tarayıcı Desteği

  • 89
  • 89
  • x
  • x

Kaynak

Şu anda API, Chrome 89 sürümünden itibaren yalnızca Chromium tabanlı tarayıcılarda desteklenmektedir. API'nin sonucu büyük ölçüde uygulamaya bağlıdır çünkü tarayıcıların bellekte nesneleri temsil etme yöntemleri ve bellek kullanımını tahmin etmenin farklı yolları vardır. Doğru hesaplama çok pahalı veya uygulanabilir değilse tarayıcılar, bazı bellek bölgelerini hesaplama dışında bırakabilir. Bu nedenle, sonuçlar tarayıcılar arasında karşılaştırılamaz. Yalnızca aynı tarayıcı için 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ı önlemek için gerekli güvenlik gereksinimlerini karşılamıyorsa performance.measureUserAgentSpecificMemory işlevi kullanım dışı kalır veya bir SecurityError hatasıyla başarısız olabilir. Bir web sayfasının COOP+COEP başlıkları ayarlayarak etkinleştirebileceği kaynaklar arası izolasyon'a 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ü çöp toplama sırasında gerçekleştirir. Yani API, vadettiği sonucu hemen çözümlemez ve bunun yerine bir sonraki çöp toplama işlemini bekler.

API'nin çağrılması, şu anda 20 saniye olarak ayarlanmış olan zaman aşımı süresinin sonunda atık toplamaya zorlar ancak daha erken de 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 ile 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 ile analiz için bir sunucuya gönderen genel bir bellek izleyicisi tanımlamaktır. En basit yöntem düzenli olarak, örneğin her M dakikada bir örnekleme yapmaktır. Ancak bu durum, örnekler arasında bellek zirveleri gerçekleşebileceği için verilerde önyargıya neden olur.

Aşağıdaki örnekte, örneklerin herhangi bir zamanda eşit olasılıkla gerçekleşme olasılığının eşit olduğunu garanti eden Poisson işlemi kullanılarak tarafsız bellek ölçümlerinin nasıl yapılacağı gösterilmektedir (demo, kaynak).

Öncelikle, rastgele bir aralıkla 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 rastgele bir aralığı milisaniye cinsinden hesaplar. İşlevin temelindeki 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çmeye 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 büyük ölçüde uygulamaya 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şebilir. Değer, geçerli 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 bölümünü açıklar ve URL ile tanımlanan bir pencere, iframe ve çalışan grubu ile ilişkilendirir. types alanında, bellekle ilişkilendirilen uygulamaya özel bellek türleri listelenir.

Tüm listeleri genel bir şekilde ele almak ve varsayımları belirli bir tarayıcıya göre gömmemek ö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 bu girişlerden hangisinin belleğe ait olduğunu ayırt edemediğini belirten birden çok giriş döndürebilir.

Geri bildirim

Web Performance Community Group ve Chrome ekibi, performance.measureUserAgentSpecificMemory() ile ilgili düşüncelerinizi ve deneyimlerinizi bizimle paylaşırsanız seviniriz.

Bize API tasarımı hakkında bilgi verin

API'de beklendiği gibi çalışmayan bir şey var mı? Yoksa fikrinizi uygulamak için gereken eksik özellikler mi var? performance.measureUserAgentSpecificMemory() GitHub deposunda spesifikasyon sorunu oluşturun veya mevcut bir sorunla ilgili düşüncelerinizi ekleyin.

Uygulamayla ilgili bir sorunu bildirin

Chrome'un uygulamasında bir hata buldunuz mu? Yoksa uygulama, spesifikasyondan farklı mı? new.crbug.com adresinden hata bildiriminde bulunun. Mümkün olduğunca fazla 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şturmalar paylaşmak için idealdir.

Desteği göster

performance.measureUserAgentSpecificMemory() uygulamasını kullanmayı düşünüyor musunuz? Herkese açık desteğiniz, Chrome ekibinin özellikleri öncelik sırasına koymasına yardımcı olur ve diğer tarayıcı satıcılarına onları desteklemenin ne kadar kritik olduğunu gösterir. @ChromiumDev adresine tweet göndererek onu nerede ve nasıl kullandığınızı bize bildirin.

Faydalı bağlantılar

Teşekkür

Chrome'daki kod incelemeleri için Domenic Denicola, Yoav Weiss, API tasarım incelemelerinden Mathias Bynens ve Dominik Inführ, Hannes Payer, Kentaro Hara ve Michael Lippautz'a teşekkür ederiz. Ayrıca, API'yi önemli ölçüde iyileştiren değerli kullanıcı geri bildirimlerinden dolayı Per Parker, Philipp Weis, Olga Belomestnykh, Matthew Bolohan ve Neil Mckay'e de teşekkür ederim.

Unsplash'te Harrison Broadbent'in hero resmi