تسجيل لقطات مجمّعة

Meggin Kearney
Meggin Kearney
Sofia Emelianova
Sofia Emelianova

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

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

أخذ لقطة

لأخذ لقطة متعدّدة، يُرجى اتّباع الخطوات التالية:

  1. في الصفحة التي تريد عرضها، افتح "أدوات مطوري البرامج" وانتقِل إلى لوحة الذاكرة.
  2. اختَر radio_button_checked نوع التحليل لأخذ لقطات لعناصر متعدّدة، ثم اختَر مثيلاً لجهاز JavaScript VM، وانقر على أخذ لقطة.

نوع تحليل محدّد ومثيل افتراضي من JavaScript

عند تحميل اللقطة وتحليلها في لوحة الذاكرة، يتم عرض الحجم الإجمالي لكائنات JavaScript التي يمكن الوصول إليها أسفل عنوان اللقطة في قسم لقطات HEAP.

الحجم الإجمالي للعناصر التي يمكن الوصول إليها.

اللقطات فقط تعرض الكائنات من الرسم البياني للذاكرة التي يمكن الوصول إليها من الكائن العمومي. دائمًا ما يبدأ التقاط لقطة بجمع البيانات غير المرغوب فيها.

لقطة مجمّعة لكائنات "عناصر" متفرقة.

محو اللقطات

لإزالة كل اللقطات، انقر على حظر محو جميع الملفات الشخصية:

محو جميع الملفات الشخصية

عرض اللقطات

لفحص لقطات من وجهات نظر مختلفة لأغراض مختلفة، حدد إحدى طرق العرض من القائمة المنسدلة في الأعلى:

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

طريقة عرض "الملخّص" التي تم اختيارها من القائمة المنسدلة في أعلى الصفحة.

العرض الملخّص

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

طريقة عرض "الملخّص" مع دالة إنشائية موسّعة.

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

تشير الأرقام الموجودة بجوار أسماء الدالة الإنشائية إلى العدد الإجمالي للكائنات التي تم إنشاؤها باستخدام الدالة الإنشائية. تُظهر طريقة العرض الملخّص أيضًا الأعمدة التالية:

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

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

الإدخالات الخاصة في "الملخص"

بالإضافة إلى التجميع حسب الدوال الإنشائية، تجمع طريقة العرض الملخّص أيضًا الكائنات حسب:

  • الدوال المضمنة مثل Array أو Object.
  • الدوال التي حددتها في التعليمة البرمجية.
  • فئات خاصة لا تستند إلى الدوال الإنشائية.

إدخالات الدالة الإنشائية.

(array)

تتضمن هذه الفئة كائنات متنوعة تشبه الصفيفة الداخلية ولا تتوافق مباشرةً مع الكائنات المرئية في JavaScript.

على سبيل المثال، يتم تخزين محتوى كائنات Array بلغة JavaScript في كائن داخلي ثانوي يُسمى (object elements)[]، لتسهيل تغيير الحجم. وبالمثل، غالبًا ما يتم تخزين السمات المسماة في عناصر JavaScript في كائنات داخلية ثانوية تُسمّى (object properties)[] ويتم إدراجها أيضًا في الفئة (array).

(compiled code)

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

يدير الإصدار 8 تلقائيًا استخدام الذاكرة في هذه الفئة. إذا تم تشغيل دالة ما عدة مرات، فسيستخدم V8 ذاكرة أكبر لهذه الدالة بحيث يمكن تشغيلها بشكل أسرع. إذا لم تعمل الدالة منذ فترة، فقد يقوم V8 بمحو البيانات الداخلية لتلك الدالة.

(concatenated string)

عندما يربط الإصدار V8 سلسلتَين، كما هو الحال مع عامل التشغيل + في JavaScript، قد يختار تمثيل النتيجة داخليًا على أنّها "سلسلة تسلسلية" تُعرَف أيضًا باسم بنية بيانات الحبل.

بدلاً من نسخ كافة أحرف السلسلتين المصدر إلى سلسلة جديدة، يخصص V8 كائنًا صغيرًا بحقلين داخليين تُسمى first وsecond، واللذين يشيران إلى سلسلتي المصدر. وهذا يتيح لـ V8 توفير الوقت والذاكرة. من منظور رمز JavaScript، هذه السلاسل هي مجرد سلاسل عادية، وتعمل مثل أي سلسلة أخرى.

InternalNode

تمثل هذه الفئة العناصر المخصصة خارج V8، مثل كائنات C++ المحددة بواسطة Blink.

للاطّلاع على أسماء فئات C++ ، يمكنك استخدام Chrome for Testing وتنفيذ ما يلي:

  1. افتح "أدوات مطوري البرامج" وفعِّل الإعدادات الإعدادات > التجارب > check_box إظهار الخيار لعرض العناصر الداخلية في لقطات مجمّعة.
  2. افتح لوحة الذاكرة واختَر radio_button_checked إضافة لقطات سريعة، وفعِّل radio_button_checked إظهار العناصر الداخلية (بما في ذلك تفاصيل إضافية خاصة بعملية التنفيذ).
  3. يُرجى إعادة تنفيذ المشكلة التي تسبّبت في احتفاظ InternalNode بمساحة كبيرة من الذاكرة.
  4. أخذ لقطة مجمّعة في هذه اللقطة، تحتوي الكائنات على أسماء فئة C++ بدلاً من InternalNode.
(object shape)

كما هو موضّح في الخصائص السريعة في V8، يتتبّع الإصدار V8 الفئات المخفية (أو الأشكال) لكي يتم تمثيل عناصر متعددة بكفاءة بالخصائص نفسها وبالترتيب نفسه. تتضمن هذه الفئة تلك الفئات المخفية المسماة system / Map (غير مرتبطة بـ JavaScript Map)، بالإضافة إلى بيانات ذات صلة.

(sliced string)

عندما يحتاج V8 إلى أخذ سلسلة فرعية، كما هو الحال عند استدعاء رمز JavaScript String.prototype.substring()، قد يختار V8 تخصيص كائن سلسلة شرائح بدلاً من نسخ جميع الأحرف ذات الصلة من السلسلة الأصلية. يحتوي هذا الكائن الجديد على مؤشر إلى السلسلة الأصلية ويصف نطاق الأحرف من السلسلة الأصلية المطلوب استخدامه.

من منظور رمز JavaScript، هذه السلاسل هي مجرد سلاسل عادية، وتعمل مثل أي سلسلة أخرى. إذا احتفظت السلسلة المقسّمة بمساحة كبيرة من الذاكرة، قد يكون البرنامج قد تسبّب في ظهور المشكلة 2869 وقد يستفيد من اتخاذ خطوات مدروسة من أجل "تحسين" السلسلة المقسّمة إلى شرائح.

system / Context

تحتوي الكائنات الداخلية من النوع system / Context على متغيّرات محلية من إغلاق، وهو نطاق JavaScript يمكن لدالة مدمجة الوصول إليه.

يحتوي كل مثيل دالة على مؤشر داخلي يشير إلى Context الذي يتم تنفيذه، وذلك لكي يتمكّن من الوصول إلى هذه المتغيرات. على الرغم من أنّ عناصر Context غير مرئية مباشرةً من JavaScript، يمكنك التحكّم فيها بشكل مباشر.

(system)

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

عرض المقارنة

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

للتأكّد من أنّ عملية معيّنة لا تؤدي إلى حدوث تسريب:

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

تُظهر طريقة العرض المقارنة الفرق بين لقطتين. عند توسيع إدخال إجمالي، تظهر مثيلات العناصر المضافة والمحذوفة:

مقارنةً باللقطة 1.

عرض الاحتواء

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

يوفر العرض عدة نقاط دخول:

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

طريقة عرض الاحتواء.

قسم "الاحتفاظ بالمستخدمين"

يعرض قسم عناصر الاحتفاظ بالبيانات في أسفل لوحة الذاكرة العناصر التي تشير إلى العنصر الذي تم اختياره في العرض.

قسم "الاحتفاظ بالبيانات".

في هذا المثال، يتم الاحتفاظ بالسلسلة المحدّدة من خلال السمة x لمثيل Item.

البحث عن عنصر محدّد

للعثور على عنصر في كومة الذاكرة المؤقتة التي تم جمعها، يمكنك البحث باستخدام Ctrl + F وإدخال رقم تعريف العنصر.

تسمية الدوال للتمييز بين حالات الإغلاق

من المفيد كثيرًا تسمية الدوال حتى تتمكن من التمييز بين حالات الإغلاق في اللقطة.

على سبيل المثال، لا يستخدم الرمز التالي الدوال المُسمّاة:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function() { // this is NOT a named function
    return largeStr;
  };

  return lC;
}

في حين أن هذا المثال ينطبق:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function lC() { // this IS a named function
    return largeStr;
  };

  return lC;
}

دالة مُسمّاة في دالة الإغلاق

الكشف عن تسرّبات DOM

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

قد يكون تسرُّب نموذج العناصر في المستند (DOM) أكبر مما تعتقد. ضع في الاعتبار المثال التالي. متى يتم جمع البيانات غير المرغوب فيها في "#tree

  var select = document.querySelector;
  var treeRef = select("#tree");
  var leafRef = select("#leaf");
  var body = select("body");

  body.removeChild(treeRef);

  //#tree can't be GC yet due to treeRef
  treeRef = null;

  //#tree can't be GC yet due to indirect
  //reference from leafRef

  leafRef = null;
  //#NOW #tree can be garbage collected

تحتفظ السمة #leaf بمرجع إلى العنصر الرئيسي (parentNode) وبشكل متكرر حتى #tree، ولذلك عندما يتم إبطال leafRef، يتم عرض الشجرة الكاملة ضمن #tree عنصر مرشَّح للحصول على تجميع البيانات المهملة.

الأشجار الفرعية في DOM