حل مشاكل الذاكرة

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

ملخّص

  • اكتشف حجم الذاكرة التي تستخدمها صفحتك حاليًا من خلال إدارة مهام Chrome.
  • يمكنك عرض استخدام الذاكرة بمرور الوقت من خلال تسجيلات "المخطط الزمني".
  • تحديد أشجار DOM المنفصلة (السبب الشائع لتسرّب الذاكرة) باستخدام لقطات لأجزاء من الذاكرة.
  • يمكنك معرفة وقت تخصيص ذكرى جديدة في كومة JavaScript من خلال تسجيلات "المخطط الزمني" المخصّص لتخصيصها.

نظرة عامة

استنادًا إلى نموذج أداء RAIL، يجب أن تركّز جهودك على المستخدمين.

مشاكل الذاكرة مهمة لأنها غالبًا ما يلاحظها المستخدمون. يمكن للمستخدمين إدراك مشكلات الذاكرة بالطرق التالية:

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

انتفاخ الذاكرة: ما مقدار "أكبر من اللازم"؟

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

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

المفتاح هنا هو استخدام نموذج RAIL والتركيز على المستخدمين. اكتشف الأجهزة الشائعة لدى المستخدمين، ثم اختبِر صفحتك على هذه الأجهزة. فإذا كانت التجربة سيئة باستمرار، فربما تتجاوز الصفحة إمكانات الذاكرة لهذه الأجهزة.

مراقبة استخدام الذاكرة في الوقت الفعلي باستخدام "إدارة مهام Chrome"

يمكنك استخدام "إدارة مهام Chrome" كنقطة بداية للتحقيق في مشكلة الذاكرة. مدير المهام عبارة عن أداة مراقبة في الوقت الفعلي تخبرك بحجم الذاكرة التي تستخدمها الصفحة حاليًا.

  1. اضغط على Shift+Esc أو انتقِل إلى قائمة Chrome الرئيسية واختَر المزيد من الأدوات > إدارة المهام لفتح "إدارة المهام".

    فتح "إدارة المهام"

  2. انقر بزر الماوس الأيمن على عنوان الجدول في "إدارة المهام" وفعِّل ذاكرة JavaScript.

    تفعيل ذاكرة JavaScript

يوضح لك هذان العمودان أشياء مختلفة حول كيفية استخدام صفحتك للذاكرة:

  • يمثّل عمود الذاكرة الذاكرة الأصلية. يتم تخزين عُقد DOM في الذاكرة الأصلية. في حال زيادة هذه القيمة، يتم إنشاء عُقد DOM.
  • ويمثّل عمود ذاكرة JavaScript كومة JavaScript. يحتوي هذا العمود على قيمتين. القيمة التي تهتم بها هي الرقم المباشر (الرقم الموجود بين قوسين). يمثل الرقم المباشر مقدار الذاكرة التي تستخدمها العناصر التي يمكن الوصول إليها على صفحتك. إذا كان هذا العدد في ازدياد، فإما أن يتم إنشاء كائنات جديدة أو أن العناصر الموجودة تنمو.

عرض صور تسرّب الذاكرة من خلال تسجيلات الأداء

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

  1. افتح لوحة الأداء في "أدوات مطوري البرامج".
  2. فعِّل مربّع الاختيار الذاكرة.
  3. سجِّل تسجيلاً.

لعرض تسجيلات الذاكرة الخاصة بالأداء، يمكنك استخدام الرمز التالي:

var x = [];

function grow() {
  for (var i = 0; i < 10000; i++) {
    document.body.appendChild(document.createElement('div'));
  }
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

في كل مرة يتم فيها الضغط على الزر المُشار إليه في الرمز البرمجي، يتم إلحاق عشرة آلاف عُقدة div بنص المستند، ويتم إرسال سلسلة مكوّنة من مليون حرف x إلى المصفوفة x. يؤدي تشغيل هذا الرمز إلى إنشاء تسجيل "المخطط الزمني" مثل لقطة الشاشة التالية:

مثال النمو البسيط

أولاً، شرح لواجهة المستخدم. يمثّل الرسم البياني HEAP في اللوحة نظرة عامة (أسفل NET) كومة JavaScript. تظهر أسفل اللوحة نظرة عامة اللوحة عرض مضاد. يمكنك هنا الاطّلاع على استخدام الذاكرة مقسمًا حسب كومة JavaScript (مثل الرسم البياني HEAP في اللوحة نظرة عامة)، والمستندات وعُقد DOM والمستمعين وذاكرة وحدة معالجة الرسومات. يؤدي تعطيل مربع اختيار إلى إخفائه من الرسم البياني.

الآن، تحليل التعليمة البرمجية مقارنة بلقطة الشاشة. إذا نظرت إلى عدّاد العقدة (الرسم البياني الأخضر)، فستلاحظ أنه يتطابق تمامًا مع التعليمة البرمجية. يزداد عدد العقدة في الخطوات المنفصلة. ويمكنك افتراض أنّ كل زيادة في عدد العُقد هي استدعاء إلى grow(). إن الرسم البياني لعناصر JavaScript (الرسم البياني الأزرق) ليس بسيطًا. تماشيًا مع أفضل الممارسات، تكون الانخفاضة الأولى في الواقع هي عملية إجبارية لجمع البيانات غير المرغوب فيها (يتم تنفيذ هذه العملية من خلال الضغط على زر جمع البيانات غير المرغوب فيها). ومع تقدّم التسجيل، يمكنك ملاحظة ارتفاع كبير في حجم كومة عناصر JavaScript. هذا أمر طبيعي ومتوقع: ينشئ رمز JavaScript عُقد DOM لكل نقرة على الزر ويقوم بالكثير من العمل عندما ينشئ السلسلة المكونة من مليون حرف. الأمر الأساسي هنا هو حقيقة أنّ كومة ذاكرة التخزين المؤقت JS ينتهي بها الأمر أعلى من بدايته (تكون "البداية" هنا هي النقطة التي تلي عملية جمع البيانات غير المرغوب فيها التي يتم فرضها). في العالم الحقيقي، إذا رأيت هذا النمط لزيادة حجم كومة JavaScript أو حجم العقدة، فمن المحتمل أن يعني ذلك تسرُّب الذاكرة.

اكتشِف تسرّبات ذاكرة شجرة نموذج العناصر (DOM) التي تم فصلها باستخدام لقطات لأجزاء من الذاكرة

يمكن أن تكون عقدة DOM غير مكتملة فقط عندما لا يكون هناك مراجع لها من شجرة DOM للصفحة أو رمز JavaScript. يُقال إنّ العقدة "مفصولة" عند إزالتها من شجرة نموذج العناصر في المستند (DOM) ولكن لا تزال بعض رموز JavaScript تشير إليها. تعد عُقد DOM المنفصلة سببًا شائعًا لتسرّب الذاكرة. ويشرح لك هذا القسم كيفية استخدام محلّل عناصر إنشاء الذاكرة في "أدوات مطوّري البرامج" لتحديد العُقد المنفصلة.

في ما يلي مثال بسيط على عُقد DOM المنفصلة.

var detachedTree;

function create() {
  var ul = document.createElement('ul');
  for (var i = 0; i < 10; i++) {
    var li = document.createElement('li');
    ul.appendChild(li);
  }
  detachedTree = ul;
}

document.getElementById('create').addEventListener('click', create);

يؤدي النقر على الزر المشار إليه في الرمز إلى إنشاء عقدة ul مع عشرة li عناصر ثانوية. تتم الإشارة إلى هذه العُقد من خلال الرمز البرمجي ولكنها غير موجودة في شجرة نموذج العناصر في المستند، لذا فهي منفصلة.

اللقطات المتعدّدة هي إحدى طرق تحديد العُقد المنفصلة. كما يوحي الاسم، توضح لك لقطات لأجزاء من الذاكرة كيفية توزيع الذاكرة بين كائنات JS وعُقد DOM لصفحتك عند وقت اللقطة.

لإنشاء لقطة، افتح "أدوات مطوري البرامج" وانتقِل إلى لوحة الذاكرة، ثم انقر على زر الاختيار لقطة ، ثم اضغط على زرّ التقاط لقطة.

أخذ لقطة لأجزاء من الذاكرة

قد تستغرق معالجة اللقطة وتحميلها بعض الوقت. بعد الانتهاء من ذلك، اختَرها من اللوحة اليمنى (باسم HEAP SNAPSHOTS).

اكتب Detached في مربّع النص فلتر الفئات للبحث عن أشجار DOM المنفصلة.

الفلترة بحثًا عن العُقد المنفصلة

وسِّع القيراط لاكتشاف شجرة منفصلة.

التحقق من الشجرة المنفصلة

تحتوي العُقد المميزة باللون الأصفر على مراجع مباشرة إليها من رمز JavaScript. لا تحتوي العُقد المميزة باللون الأحمر على مراجع مباشرة. وهي تعيش فقط لأنها جزء من شجرة العقدة الصفراء. بشكلٍ عام، تحتاج إلى التركيز على العُقد الصفراء. أصلح التعليمات البرمجية حتى لا تكون العقدة الصفراء نشطة لفترة أطول مما ينبغي، ويتم التخلص أيضًا من العقد الحمراء التي تعد جزءًا من شجرة العقدة الصفراء.

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

فحص عقدة صفراء

التعرّف على تسرُّب الذاكرة لأجزاء من JavaScript باستخدام "المخططات الزمنية للتخصيص"

"المخطط الزمني لتخصيص" هو أداة أخرى يمكنها مساعدتك في تتبُّع تسرُّب الذاكرة في كومة JavaScript البرمجية.

لتوضيح المخطط الزمني للتخصيص، ضع الرمز التالي في الاعتبار:

var x = [];

function grow() {
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

في كل مرة يتم فيها الضغط على الزر المُشار إليه في الرمز، تتم إضافة سلسلة من مليون حرف إلى المصفوفة x.

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

أثناء التسجيل، لاحِظ ما إذا كانت هناك أي أشرطة زرقاء تظهر في "المخطط الزمني" للتخصيص، كما هو الحال في لقطة الشاشة أدناه.

تخصيصات جديدة

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

المخطط الزمني لعملية التخصيص المكبرة

وسِّع العنصر وانقر على قيمته للاطّلاع على مزيد من التفاصيل عنه في لوحة الكائن. على سبيل المثال، في لقطة الشاشة أدناه، يمكنك ملاحظة أنّه قد تم تخصيصه للمتغيّر x في نطاق Window، وذلك من خلال الاطّلاع على تفاصيل العنصر الذي تم تخصيصه مؤخرًا.

تفاصيل العنصر

التحقق من تخصيص الذاكرة حسب الدالة

استخدِم النوع عينة التخصيص في لوحة الذاكرة لعرض تخصيص الذاكرة حسب وظيفة JavaScript.

محلّل توزيع التسجيلات

  1. حدِّد زر الاختيار عينة التخصيص. إذا كان هناك عامل على الصفحة، يمكنك اختياره كهدف لإنشاء الملفات الشخصية باستخدام القائمة المنسدلة بجانب الزر ابدأ.
  2. اضغط على زر البدء.
  3. نفِّذ الإجراءات على الصفحة التي تريد التحقيق فيها.
  4. اضغط على الزر إيقاف عند الانتهاء من جميع الإجراءات.

يعرض لك "أدوات مطوّري البرامج" تفاصيل تخصيص الذاكرة حسب الوظيفة. طريقة العرض التلقائية هي كثيفة (من أسفل لأعلى)، وتعرض الدوال التي خصّصت أكبر قدر من الذاكرة في الأعلى.

الملف الشخصي للتخصيص

رصد مجموعات القمامة بشكل متكرر

إذا كانت صفحتك تتوقّف مؤقتًا بشكل متكرر، قد يعني ذلك أنّك تواجه مشاكل في جمع البيانات غير المرغوب فيها.

يمكنك استخدام "إدارة مهام Chrome" أو تسجيلات ذاكرة "المخطط الزمني" لاكتشاف مجموعات البيانات غير المرغوب فيها المتكررة. في "إدارة المهام"، تمثل قيم الذاكرة أو ذاكرة JavaScript التي تتناقص وتناقص بشكل متكرر مجموعات البيانات غير المرغوب فيها المتكررة. في تسجيلات "المخطط الزمني"، تشير الرسوم البيانية التي تشهد صعود وهبوط عدد العناصر غير المرغوب فيها أو كومة JavaScript بشكل متكرر إلى تجميع البيانات غير المرغوب فيها بشكل متكرر.

بعد تحديد المشكلة، يمكنك استخدام تسجيل "المخطط الزمني" للتخصيص لمعرفة مكان تخصيص الذاكرة والوظائف التي تتسبّب في التخصيص.