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

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

Brendan Kenny
Brendan Kenny
Ulan Degenbaev
Ulan Degenbaev

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 nesneye artık ihtiyaç duyulmadığında bunu algılamak ve temel bellek parçasını boşaltmak için atık toplar.

Ancak algılama mükemmel değildir ve mükemmel algılamanın imkansız bir görev olduğu kanıtlanmıştır. Bu nedenle tarayıcılar, "nesne gerekiyor" kavramını "nesne erişilebilir" kavramıyla tahmin eder. Web sayfası bir nesneye değişkenleri ve diğer erişilebilir nesnelerin alanları aracılığıyla 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 b dizisi artık gerekli değildir, ancak geri çağırmada object.b aracılığıyla hâlâ ulaşılabilir olduğundan tarayıcı bu diziyi geri almaz. Bu nedenle, daha büyük dizinin belleği sızdırılır.

Bellek sızıntıları Web'de yaygındır. Etkinlik işleyicinin kaydını silmeyi unutarak, iframe'den nesneleri yanlışlıkla yakalayarak, bir çalışanı kapatmayarak, nesneleri dizilerde biriktirerek ve benzeri işlemleri kolayca uygulayabilirsiniz. Bir web sayfasında bellek sızıntısı varsa bellek kullanımı zamanla artar ve web sayfası yavaş ve kullanıcılara şişmiş görünür.

Bu sorunu çözmenin ilk adımı problemi ölçmektir. Yeni performance.measureUserAgentSpecificMemory() API, geliştiricilerin üretimde web sayfalarının bellek kullanımını ölçmesine ve böylece yerel testlerden geçen 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. Aradaki 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 rastgele devre dışı bırakılabilir. Eski API, "yığın" gibi uygulamaya özgü terimlerle tanımlandığından bu API'yi standartlaştırmak bir umutsuzdur.

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 oluşturulması biraz zaman alabilir. Diğer tarayıcıların, atık toplamaya gerek kalmadan yeni API'yi 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, üretimden gelen 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ılama.
  • Bellek üzerindeki etkisini değerlendirmek ve bellek sızıntılarını tespit etmek için yeni bir özelliğe A/B testi yapma.
  • 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

Chrome 89 sürümünden itibaren API şu anda yalnızca Chromium tabanlı tarayıcılarda desteklenmektedir. Tarayıcıların bellekteki nesneleri temsil etmek ve bellek kullanımını tahmin etmek için farklı yolları olduğundan API'nin sonucu uygulamaya büyük ölçüde bağlıdır. Doğru hesaplama çok pahalı veya uygulanabilir değilse tarayıcılar bazı bellek bölgelerini hesaplamaya dahil etmeyebilir. Dolayısıyla, 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ı önlemeye yönelik güvenlik gereksinimlerini karşılamıyorsa performance.measureUserAgentSpecificMemory işlevi kullanılamaz olur veya SecurityError hatasıyla başarısız olabilir. Bu işlem, bir web sayfasının COOP+COEP başlıklarını 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 vaat edilen sonucu 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 saniye olarak ayarlanmıştır ancak daha kısa sürede gerçekleşebilir. Chrome'un --enable-blink-features='ForceEagerMeasureMemory' komut satırı işaretiyle başlatılması, zaman aşımını sıfıra indirir ve yerel hata ayıklama ve test işlemleri için faydalı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 global bellek izleyicisi tanımlamaktır. En basit yöntem periyodik olarak (örneğin, M dakikada bir) örnekleme yapmaktır. Ancak bu durum, örnekler arasında bellek tepe noktaları olabileceği için verilerde sapmaya neden olur.

Aşağıdaki örnekte, Poisson işlemi kullanarak tarafsız bellek ölçümlerinin nasıl yapılacağı gösterilmektedir. Bu yöntem, örneklerin herhangi bir zamanda aynı sıklıkta gerçekleşme olasılığının da eşit olduğunu garanti etmektedir (demo, kaynak).

Öncelikle rastgele bir aralıkla setTimeout() kullanarak bir sonraki bellek ölçümünü programlayan 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 olacağı ş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 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şiklik gösterebilir. Bu değer tüm iframe'lerin, ilgili pencerelerin ve geçerli işlemdeki 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ı açıklar ve bunu URL ile tanımlanan bir dizi pencere, iFrame ve çalışanla ilişkilendirir. types alanında, bellekle ilişkili uygulamaya özel bellek türleri listelenir.

Tüm listeleri genel bir şekilde ele almak ve belirli bir tarayıcıya dayalı varsayımları doğrudan kodlamamak önemlidir. Örneğin, bazı tarayıcılar boş breakdown veya boş attribution döndürebilir. Diğer tarayıcılar, attribution içinde bu girişlerden hangisinin belleğe sahip olduğunu ayırt edemediğini gösteren 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.

Bize API tasarımı hakkında bilgi verin

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

Uygulamayla ilgili bir sorunu bildirin

Chrome'un uygulanmasıyla ilgili bir hata buldunuz mu? 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şturmalar paylaşmak için idealdir.

Desteğinizi gösterin

performance.measureUserAgentSpecificMemory() kullanmayı planlıyor musunuz? Herkese açık desteğiniz, Chrome ekibinin özellikleri önceliklendirmesine yardımcı olur ve diğer tarayıcı tedarikçilerine, bunları desteklemenin ne kadar kritik olduğunu gösterir. @ChromiumDev'e bir tweet gönderin ve uygulamayı nerede ve nasıl kullandığınızı bize bildirin.

Faydalı bağlantılar

Teşekkür

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

Harrison Broadbent'ten Unsplash'teki hero resim