measureUserAgentspecificMemory() की मदद से, अपने वेब पेज के कुल मेमोरी इस्तेमाल पर नज़र रखें

प्रोडक्शन में अपने वेब पेज के मेमोरी इस्तेमाल को मेज़र करने का तरीका जानें, ताकि परफ़ॉर्मेंस में गिरावट का पता लगाया जा सके.

Ulan Degenbaev
Ulan Degenbaev

ब्राउज़र, वेब पेजों की मेमोरी को अपने-आप मैनेज करते हैं. जब भी कोई वेब पेज कोई ऑब्जेक्ट बनाता है, तो ब्राउज़र ऑब्जेक्ट को सेव करने के लिए, "हुड के नीचे" मेमोरी का एक हिस्सा तय करता है. मेमोरी एक सीमित संसाधन है. इसलिए, ब्राउज़र गै़रबेज कलेक्शन की प्रोसेस करता है. इससे यह पता चलता है कि किसी ऑब्जेक्ट की अब ज़रूरत नहीं है और उससे जुड़ी मेमोरी को खाली किया जा सकता है.

हालांकि, यह तरीका हमेशा काम नहीं करता. साथ ही, यह साबित हो चुका है कि किसी भी वीडियो में मौजूद सभी ऑब्जेक्ट का पता लगाना असंभव है. इसलिए, ब्राउज़र "किसी ऑब्जेक्ट की ज़रूरत है" के बजाय "किसी ऑब्जेक्ट को ऐक्सेस किया जा सकता है" के हिसाब से काम करते हैं. अगर वेब पेज, अपने वैरिएबल और ऐक्सेस किए जा सकने वाले अन्य ऑब्जेक्ट के फ़ील्ड के ज़रिए किसी ऑब्जेक्ट तक नहीं पहुंच सकता, तो ब्राउज़र सुरक्षित तरीके से उस ऑब्जेक्ट को फिर से हासिल कर सकता है. इन दोनों के बीच के अंतर की वजह से, मेमोरी लीक होती है. इस बारे में नीचे दिए गए उदाहरण में बताया गया है.

const object = {a: new Array(1000), b: new Array(2000)};
setInterval(() => console.log(object.a), 1000);

यहां बड़े कलेक्शन b की ज़रूरत नहीं है, लेकिन ब्राउज़र इसे फिर से हासिल नहीं करता, क्योंकि यह अब भी कॉलबैक में object.b के ज़रिए ऐक्सेस किया जा सकता है. इस वजह से, बड़े ऐरे की मेमोरी लीक हो जाती है.

मेमोरी लीक की समस्या वेब पर आम तौर पर होती है. किसी इवेंट के लिसनर को अनरजिस्टर करना भूल जाने, किसी iframe से गलती से ऑब्जेक्ट कैप्चर करने, किसी वर्कर्स को बंद न करने, ऑब्जेक्ट को ऐरे में इकट्ठा करने वगैरह की वजह से, मेमोरी लीक हो सकती है. अगर किसी वेब पेज में मेमोरी लीक है, तो समय के साथ उसकी मेमोरी का इस्तेमाल बढ़ता जाता है. साथ ही, उपयोगकर्ताओं को वेब पेज धीमा और बड़ा दिखता है.

इस समस्या को हल करने का पहला चरण, इसे मेज़र करना है. नए performance.measureUserAgentSpecificMemory() एपीआई की मदद से, डेवलपर अपने वेब पेजों के प्रोडक्शन में मेमोरी के इस्तेमाल को मेज़र कर सकते हैं. इससे, वे मेमोरी के ऐसे लीक का पता लगा सकते हैं जो लोकल टेस्टिंग में नहीं दिखते.

performance.measureUserAgentSpecificMemory(), लेगसी performance.memory एपीआई से किस तरह अलग है?

अगर आपको मौजूदा नॉन-स्टैंडर्ड performance.memory एपीआई के बारे में पता है, तो हो सकता है कि आप सोच रहे हों कि नया एपीआई इससे कैसे अलग है. मुख्य अंतर यह है कि पुराना एपीआई, JavaScript ढेर का साइज़ दिखाता है, जबकि नया एपीआई, वेब पेज के इस्तेमाल की गई मेमोरी का अनुमान लगाता है. यह अंतर तब अहम हो जाता है, जब Chrome एक ही हेप को कई वेब पेजों (या एक ही वेब पेज के कई इंस्टेंस) के साथ शेयर करता है. ऐसे मामलों में, पुराने एपीआई का नतीजा मनमुताबिक हो सकता है. पुराने एपीआई को लागू करने के लिए, "हीप" जैसे खास शब्दों का इस्तेमाल किया जाता है. इसलिए, इसे स्टैंडर्ड बनाना मुमकिन नहीं है.

एक और अंतर यह है कि नया एपीआई, ग़ैर-ज़रूरी डेटा हटाने के दौरान मेमोरी मेज़रमेंट करता है. इससे नतीजों में ग़ैर-ज़रूरी जानकारी कम हो जाती है. हालांकि, नतीजे मिलने में थोड़ा समय लग सकता है. ध्यान दें कि अन्य ब्राउज़र, गै़रबेज कलेक्शन के बिना नए एपीआई को लागू करने का फ़ैसला ले सकते हैं.

इस्तेमाल के सुझाए गए उदाहरण

किसी वेब पेज का मेमोरी इस्तेमाल, इवेंट, उपयोगकर्ता ऐक्शन, और 'ट्रैश' इकट्ठा करने के समय पर निर्भर करता है. इसलिए, मेमोरी मेज़रमेंट एपीआई का मकसद, प्रोडक्शन से मेमोरी के इस्तेमाल का डेटा इकट्ठा करना है. अलग-अलग कॉल के नतीजे कम काम के होते हैं. इस्तेमाल के उदाहरण:

  • वेब पेज के नए वर्शन को रोल आउट करने के दौरान, नई मेमोरी लीक का पता लगाने के लिए, रिग्रेशन का पता लगाना.
  • किसी नई सुविधा की A/B टेस्टिंग की जा रही है, ताकि यह पता लगाया जा सके कि यह सुविधा रैम पर कितना असर डालती है और रैम का इस्तेमाल कितना होता है.
  • मेमोरी के इस्तेमाल को सेशन की अवधि से जोड़कर, मेमोरी लीक की मौजूदगी या अनुपस्थिति की पुष्टि करना.
  • मेमोरी के इस्तेमाल का कुल असर समझने के लिए, मेमोरी के इस्तेमाल को उपयोगकर्ता मेट्रिक के साथ जोड़ना.

ब्राउज़र के साथ काम करना

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 89.
  • Edge: 89.
  • Firefox: यह सुविधा काम नहीं करती.
  • Safari: यह सुविधा काम नहीं करती.

सोर्स

फ़िलहाल, यह एपीआई सिर्फ़ Chromium पर आधारित ब्राउज़र पर काम करता है. यह सुविधा, Chrome 89 से शुरू हुई थी. एपीआई का नतीजा, लागू करने के तरीके पर बहुत ज़्यादा निर्भर करता है. इसकी वजह यह है कि ब्राउज़र में ऑब्जेक्ट को मेमोरी में दिखाने के अलग-अलग तरीके होते हैं. साथ ही, मेमोरी के इस्तेमाल का अनुमान लगाने के अलग-अलग तरीके भी होते हैं. अगर मेमोरी का सही हिसाब लगाना बहुत महंगा या असंभव है, तो ब्राउज़र कुछ मेमोरी क्षेत्रों को हिसाब लगाने से बाहर रख सकते हैं. इसलिए, अलग-अलग ब्राउज़र के नतीजों की तुलना नहीं की जा सकती. सिर्फ़ एक ही ब्राउज़र के नतीजों की तुलना करना ही सही होता है.

performance.measureUserAgentSpecificMemory() का इस्तेमाल करना

फ़ीचर का पता लगाना

अगर एक्सीक्यूशन एनवायरमेंट, क्रॉस-ऑरिजिन जानकारी लीक होने से रोकने के लिए सुरक्षा से जुड़ी ज़रूरी शर्तें पूरी नहीं करता है, तो performance.measureUserAgentSpecificMemory फ़ंक्शन उपलब्ध नहीं होगा या SecurityError के साथ काम नहीं करेगा. यह क्रॉस-ऑरिजिन आइसोलेशन पर निर्भर करता है. कोई वेब पेज, COOP+COEP हेडर सेट करके इसे चालू कर सकता है.

रनटाइम के दौरान सहायता का पता लगाया जा सकता है:

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);
}

स्थानीय टेस्टिंग

Chrome, गै़रबेज कलेक्शन के दौरान मेमोरी मेज़रमेंट करता है. इसका मतलब है कि एपीआई, नतीजे के वादे को तुरंत हल नहीं करता है. इसके बजाय, अगले गै़रबेज कलेक्शन का इंतज़ार करता है.

एपीआई को कॉल करने पर, कुछ समय के टाइम आउट के बाद, गै़रबेज कलेक्शन अपने-आप शुरू हो जाता है. फ़िलहाल, यह टाइम आउट 20 सेकंड पर सेट है. हालांकि, यह टाइम आउट इससे पहले भी शुरू हो सकता है. --enable-blink-features='ForceEagerMeasureMemory' कमांड-लाइन फ़्लैग के साथ Chrome को शुरू करने पर, टाइम आउट शून्य हो जाता है. यह स्थानीय डीबगिंग और टेस्टिंग के लिए फ़ायदेमंद है.

उदाहरण

एपीआई का सुझाया गया इस्तेमाल, एक ग्लोबल मेमोरी मॉनिटर तय करना है. यह पूरे वेब पेज के मेमोरी इस्तेमाल का सैंपल लेता है और एग्रीगेशन और विश्लेषण के लिए नतीजों को सर्वर पर भेजता है. सबसे आसान तरीका यह है कि समय-समय पर सैंपल लिया जाए. उदाहरण के लिए, हर M मिनट में. हालांकि, इससे डेटा में गड़बड़ी हो सकती है, क्योंकि सैंपल के बीच में मेमोरी में अचानक बढ़ोतरी हो सकती है.

नीचे दिए गए उदाहरण में, पॉइसन प्रोसेस का इस्तेमाल करके, बिना किसी पक्षपात के मेमोरी मेज़रमेंट करने का तरीका बताया गया है. इससे यह पक्का होता है कि किसी भी समय सैंपल मिलने की संभावना एक जैसी होती है (डेमो, सोर्स).

सबसे पहले, एक फ़ंक्शन तय करें जो setTimeout() का इस्तेमाल करके, यादृच्छिक इंटरवल के साथ अगली मेमोरी मेज़रमेंट को शेड्यूल करे.

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() फ़ंक्शन, मिलीसेकंड में एक रैंडम इंटरवल का हिसाब लगाता है, ताकि औसतन हर पांच मिनट में एक मेज़रमेंट हो. अगर आपको फ़ंक्शन के पीछे के गणित में दिलचस्पी है, तो एक्सपोनेंशियल डिस्ट्रिब्यूशन देखें.

function measurementInterval() {
  const MEAN_INTERVAL_IN_MS = 5 * 60 * 1000;
  return -Math.log(Math.random()) * MEAN_INTERVAL_IN_MS;
}

आखिर में, असाइन किए गए फ़ंक्शन के साथ काम करने वाला performMeasurement() फ़ंक्शन, एपीआई को कॉल करता है, नतीजे को रिकॉर्ड करता है, और अगले मेज़रमेंट को शेड्यूल करता है.

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();
}

आखिर में, मेज़रमेंट शुरू करें.

// Start measurements.
scheduleMeasurement();

नतीजा कुछ ऐसा दिख सकता है:

// 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']
    },
  ],
}

मेमोरी के इस्तेमाल का कुल अनुमान, bytes फ़ील्ड में दिखता है. यह वैल्यू, लागू करने के तरीके पर बहुत ज़्यादा निर्भर करती है. साथ ही, इसकी तुलना अलग-अलग ब्राउज़र के बीच नहीं की जा सकती. यह एक ही ब्राउज़र के अलग-अलग वर्शन के बीच भी बदल सकता है. इस वैल्यू में, मौजूदा प्रोसेस में सभी iframe, मिलती-जुलती विंडो, और वेब वर्कर की JavaScript और डीओएम मेमोरी शामिल होती है.

breakdown सूची में, इस्तेमाल की गई मेमोरी के बारे में ज़्यादा जानकारी मिलती है. हर एंट्री में मेमोरी के किसी हिस्से के बारे में बताया जाता है. साथ ही, उसे यूआरएल से पहचानी गई विंडो, iframe, और वर्कर्स के सेट के लिए एट्रिब्यूट किया जाता है. types फ़ील्ड में, मेमोरी से जुड़े लागू करने के हिसाब से मेमोरी टाइप की सूची होती है.

सभी सूचियों को सामान्य तरीके से इस्तेमाल करना ज़रूरी है. साथ ही, किसी खास ब्राउज़र के आधार पर, अनुमान को हार्डकोड न करें. उदाहरण के लिए, कुछ ब्राउज़र में breakdown या attribution खाली हो सकता है. अन्य ब्राउज़र, attribution में कई एंट्री दिखा सकते हैं. इससे पता चलता है कि वे यह पता नहीं लगा पाए कि इनमें से किस एंट्री के पास मेमोरी है.

सुझाव/राय दें या शिकायत करें

वेब परफ़ॉर्मेंस कम्यूनिटी ग्रुप और Chrome टीम को, performance.measureUserAgentSpecificMemory() के बारे में आपके विचार और अनुभव सुनकर खुशी होगी.

हमें एपीआई के डिज़ाइन के बारे में बताएं

क्या एपीआई में कोई ऐसी चीज़ है जो उम्मीद के मुताबिक काम नहीं करती? या क्या आपके आइडिया को लागू करने के लिए, ऐसी प्रॉपर्टी मौजूद नहीं हैं जो ज़रूरी हैं? performance.measureUserAgentSpecificMemory() GitHub रेपो पर, स्पेसिफ़िकेशन से जुड़ी समस्या दर्ज करें या किसी मौजूदा समस्या में अपने सुझाव जोड़ें.

लागू करने से जुड़ी समस्या की शिकायत करना

क्या आपको Chrome में इस सुविधा को लागू करने में कोई गड़बड़ी मिली? या क्या इसे लागू करने का तरीका, स्पेसिफ़िकेशन से अलग है? new.crbug.com पर जाकर, गड़बड़ी की शिकायत करें. इसमें ज़्यादा से ज़्यादा जानकारी शामिल करें. साथ ही, गड़बड़ी को दोहराने के लिए आसान निर्देश दें. साथ ही, कॉम्पोनेंट को Blink>PerformanceAPIs पर सेट करें. Glitch, तुरंत और आसानी से समस्या की जानकारी शेयर करने के लिए बहुत अच्छा है.

क्रिएटर के लिए अपना सपोर्ट दिखाना

क्या आपको performance.measureUserAgentSpecificMemory() का इस्तेमाल करना है? सार्वजनिक तौर पर सहायता पाने की सुविधा से, Chrome की टीम को सुविधाओं को प्राथमिकता देने में मदद मिलती है. साथ ही, इससे ब्राउज़र के अन्य वेंडर को यह पता चलता है कि इन सुविधाओं को उपलब्ध कराना कितना ज़रूरी है. @ChromiumDev पर ट्वीट करें और हमें बताएं कि इसका इस्तेमाल कहां और कैसे किया जा रहा है.

मदद के लिए लिंक

आभार

एपीआई डिज़ाइन की समीक्षा करने के लिए, Domenic Denicola, Yoav Weiss, और Mathias Bynens का बहुत-बहुत धन्यवाद. साथ ही, Chrome में कोड की समीक्षा करने के लिए, Dominik Inführ, Hannes Payer, Kentaro Hara, और Michael Lippautz का भी बहुत-बहुत धन्यवाद. हम उपयोगकर्ताओं के ज़रूरी सुझाव, शिकायत या राय देने के लिए, Per Parker, Philipp Weis, Olga Belomestnykh, Matthew Bolohan, और Neil Mckay का भी धन्यवाद करते हैं. इनकी मदद से, एपीआई को बेहतर बनाया जा सका.

Unsplash पर हैरिसन ब्रॉडबेंट की हीरो इमेज