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 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

Tarayıcı Desteği

  • Chrome: 89.
  • Edge: 89.
  • Firefox: Desteklenmez.
  • Safari: Desteklenmez.

Kaynak

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

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