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

Gerileme tespit etmek için web sayfanızı üretim ortamında nasıl ölçeceğinizi öğrenin.

Ulan Degenbaev
Ulan Degenbaev

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 "altyapıda" bir bellek alanı 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, "nesneye ihtiyaç var" fikrini "nesneye erişilebilir" fikriyle yaklaşık olarak eşleştirir. 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 neden olur.

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 bu 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. Bir etkinliği dinleyicinin kaydını silmeyi unutarak, bir iframe'den yanlışlıkla nesne yakalayarak, bir çalışanı kapatmayarak, nesneleri dizilerde toplayarak vb. bir sızıntı oluşturmak 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ı, sorunu ö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(), eski performance.memory API'den nasıl farklıdır?

Mevcut standart olmayan performance.memory API'yi biliyorsanız yeni API'nin bu API'den ne açıdan farklı olduğunu 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ı

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. Tekil 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 gerileme algılama.
  • Bellek üzerindeki etkisini değerlendirmek ve bellek sızıntısı olup olmadığı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 nesneleri bellekte farklı şekillerde temsil ettiği ve bellek kullanımını farklı şekillerde tahmin ettiği için 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ı, kaynaktan kaynaka bilgi sızıntısını önlemeyle ilgili güvenlik şartlarını 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, bellek ölçümünü çöp toplama sırasında gerçekleştirir. Bu, API'nin sonuç vaadini hemen çözmediği, bunun yerine bir sonraki çöp toplama işlemini beklediği anlamına gelir.

API'nin çağrılması, belirli bir zaman aşımı süresinden sonra bir çöp toplama işlemini zorunlu kılar. Bu süre şu anda 20 saniye olarak 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 düşürür 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 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, async performMeasurement() işlevi API'yi çağırır, sonucu kaydeder ve 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. Hatta aynı tarayıcının farklı sürümleri arasında bile değişiklik gösterebilir. 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ı 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 şey var mı? Yoksa fikrinizi uygulamak için ihtiyaç duyduğunuz özellikler eksik mi? performance.measureUserAgentSpecificMemory() GitHub deposunda spesifikasyon sorunu oluşturun 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 adresinden hata kaydı oluşturun. Mümkün olduğunca fazla ayrıntı eklediğinizden, hatayı yeniden oluşturmayla ilgili basit talimatlar sağladığınızdan ve Bileşenler'in Blink>PerformanceAPIs olarak ayarlandığından 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'ta Harrison Broadbent tarafından oluşturulan lokomotif resim