راقِب إجمالي استخدام الذاكرة في صفحة الويب من خلال قياسUserAgentspecificMemory()

تعرَّف على طريقة قياس استخدام الذاكرة لصفحة الويب في عملية الإنتاج لرصد أي تراجع في أداء الصفحة.

Brendan Kenny
Brendan Kenny
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() API تتيح للمطوّرين قياس استخدام الذاكرة لصفحات الويب في عملية الإنتاج وبالتالي اكتشاف مساحة الذاكرة من التسريبات التي تمر من خلال الاختبار المحلي.

ما هي أوجه الاختلاف بين performance.measureUserAgentSpecificMemory() وperformance.memory API القديمة؟

إذا كنت على دراية بواجهة برمجة تطبيقات performance.memory غير العادية الحالية، قد تتساءل عن مدى اختلاف واجهة برمجة التطبيقات الجديدة عنها. يتمثل الاختلاف الرئيسي في أن واجهة برمجة التطبيقات القديمة تُرجع حجم كومة JavaScript، بينما تعرض واجهة برمجة التطبيقات الجديدة تقدير الذاكرة المستخدمة في صفحة الويب. يصبح هذا الاختلاف هامًا عندما يشارك Chrome كومة الذاكرة المتعددة نفسه مع صفحات ويب متعددة (أو نسخ متعددة من صفحة الويب نفسها). في مثل هذه الحالات، يمكن أن تكون نتيجة قد يتم إيقاف واجهة برمجة التطبيقات بشكل عشوائي. بما أنه تم تحديد واجهة برمجة التطبيقات القديمة في بعبارات خاصة بالتنفيذ مثل "heap"، إلا أن توحيدها أمر مستبعد.

وهناك اختلاف آخر وهو أن واجهة برمجة التطبيقات الجديدة تنفذ قياس الذاكرة أثناء جمع البيانات المهملة. ومن شأن هذا تقليل التشويش في النتائج، ولكنه قد يستغرق أثناء التوصل إلى النتائج. يُرجى العلم أنّ المتصفحات الأخرى قد تقرر تنفيذ واجهة برمجة التطبيقات الجديدة بدون الاعتماد على البيانات المهملة.

حالات الاستخدام المقترَحة

يعتمد استخدام الذاكرة لصفحة الويب على توقيت الأحداث وإجراءات المستخدم البيانات غير المرغوب فيها. ولهذا السبب تم تصميم واجهة برمجة تطبيقات قياس الذاكرة هو تجميع بيانات استخدام الذاكرة من الإنتاج. نتائج المكالمات الفردية أقل فائدة. أمثلة على حالات الاستخدام:

  • رصد التراجع أثناء طرح إصدار جديد من صفحة الويب لرصد حالات تسرّب الذاكرة الجديدة
  • اختبار A/B لميزة جديدة لتقييم تأثيرها على الذاكرة ورصد تسرُّب الذاكرة
  • ربط استخدام الذاكرة بمدة الجلسة للتحقّق من توفُّر حالات تسرُّب للذاكرة أو عدم توفّرها.
  • ربط استخدام الذاكرة بمقاييس المستخدم لفهم التأثير الإجمالي لاستخدام الذاكرة

توافُق المتصفح

دعم المتصفح

  • Chrome: 89.
  • الحافة: 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 ثانية، ولكن قد يحدث ذلك في وقت أقرب. بدء تشغيل Chrome يتم تقليل علامات سطر الأوامر "--enable-blink-features='ForceEagerMeasureMemory'" تنتهي المهلة إلى صفر، ويكون مفيدًا لتصحيح الأخطاء والاختبار على الجهاز.

مثال

الاستخدام الموصى به لواجهة برمجة التطبيقات هو تحديد أداة مراقبة عامة للذاكرة أخذ عينات من استخدام الذاكرة لصفحة الويب بأكملها وإرسال النتائج إلى خادم للتجميع والتحليل. وأبسط طريقة هي أخذ العينات بشكل دوري، مثال كل 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. هذه القيمة تعتمد على عملية التنفيذ بشكل كبير ولا يمكن مقارنتها على مستوى المتصفحات قد حتى تتغير بين إصدارات مختلفة من نفس المتصفح. تتضمن القيمة ذاكرة JavaScript وDOM لجميع إطارات iframe والنوافذ ذات الصلة وعاملي الويب في للعملية الحالية.

توفّر قائمة "breakdown" معلومات إضافية عن الذاكرة المستخدَمة. على كل هذا الإدخال يصف جزءًا من الذاكرة وينسبه إلى مجموعة من النوافذ وإطارات iframe والعاملين الذين تم تحديدهم بواسطة عنوان URL. يسرد الحقل types أنواع الذاكرة الخاصة بعملية التنفيذ والمرتبطة بالذاكرة.

من المهم التعامل مع جميع القوائم بطريقة عامة وعدم التعامل مع الترميز الثابت افتراضات معينة تستند إلى متصفح معين. على سبيل المثال، قد تتضمن بعض المتصفحات تكون قيمة breakdown فارغة أو attribution فارغة. وهناك متصفحات أخرى قد إرجاع إدخالات متعددة في اللغة attribution تشير إلى عدم تمكنها من التمييز أي من هذه الإدخالات يملك الذاكرة.

ملاحظات

تفضِّل مجموعة منتدى أداء الويب وفريق Chrome أن تستمع إلى أفكارك وخبراتك في performance.measureUserAgentSpecificMemory()

أخبِرنا عن تصميم واجهة برمجة التطبيقات

هل هناك أي مشكلة في واجهة برمجة التطبيقات لا تعمل كما هو متوقع؟ أم أن هناك الخصائص المفقودة التي تحتاجها لتنفيذ فكرتك؟ الإبلاغ عن مشكلة في المواصفات على performance.measureUserAgentSpecificMemory() GitHub أو يمكن إضافة أفكارك بشأن مشكلة حالية.

الإبلاغ عن مشكلة في التنفيذ

هل واجهت مشكلة في التنفيذ في Chrome؟ أم أن التنفيذ عن المواصفات؟ يُرجى الإبلاغ عن الخطأ على new.crbug.com. تأكد من وذكر أكبر قدر ممكن من التفاصيل، وقدم تعليمات بسيطة لإعادة إنتاج الخطأ، وضبط المكونات على Blink>PerformanceAPIs. تعمل ميزة الخطأ بشكلٍ رائع لمشاركة النسخ المُعاد إنتاجها بسرعة وسهولة.

إظهار الدعم

هل تخطّط لاستخدام "performance.measureUserAgentSpecificMemory()"؟ الدعم العام مساعدة فريق Chrome في تحديد أولويات الميزات وتوضيح لموردي المتصفّحات الآخرين أمرًا بالغ الأهمية لدعمهم. إرسال تغريدة إلى @ChromiumDev عليك إعلامنا بمكان تطبيقك وطريقة استخدامه

روابط مفيدة

شكر وتقدير

شكرًا جزيلاً لدومينيك دينيكولا وياف وايس وماتياس بينينز لمراجعات تصميم واجهة برمجة التطبيقات، و"دومينيك إنفور" و"هانس باير" و"كينتارو هارا" و"مايكل ليبوتز" لمراجعة التعليمات البرمجية في متصفح Chrome. أشكر أيضًا "بير باركر" و"فيليب وايس" و"أولغا بيلومستنيخ" و"ماثيو" وبولوهان ونيل ماكاي لتقديم ملاحظات قيّمة للمستخدمين قامت بتحسين واجهة برمجة التطبيقات.

صورة رئيسية من إعداد هاريسون برودبنت على قناة Un التصميم