التعرّف على كيفية تسجيل لقطات لأجزاء من الذاكرة باستخدام الذاكرة > الملفات الشخصية > لقطة لأجزاء من الذاكرة والعثور على حالات تسرّب الذاكرة
يعرض محلّل لقطات لأجزاء من الذاكرة توزيع الذاكرة حسب كائنات JavaScript في صفحتك وعُقد DOM ذات الصلة. ويمكنك استخدام هذه الأداة لأخذ لقطات لأجزاء من الذاكرة في JavaScript وتحليل الرسوم البيانية للذاكرة ومقارنة اللقطات والعثور على تسرُّب الذاكرة. لمزيد من المعلومات، اطّلِع على شجرة الاحتفاظ بالكائنات.
التقاط لقطة
لالتقاط لقطة لأجزاء من الذاكرة:
- على الصفحة التي تريد تحليلها، افتح "أدوات مطوري البرامج" وانتقِل إلى لوحة الذاكرة.
- اختَر نوع الملف التعريفي لـ لقطة لأجزاء من الذاكرة، ثم اختَر مثيل جهاز افتراضي للغة JavaScript، وانقر على أخذ لقطة.
عند تحميل لوحة الذاكرة وتحليل اللقطة، يتم عرض الحجم الإجمالي لكائنات JavaScript التي يمكن الوصول إليها أسفل عنوان اللقطة في قسم لقطات HEAP.
لا تعرض اللقطات سوى العناصر من الرسم البياني للذاكرة التي يمكن الوصول إليها من الكائن الشامل. دائمًا ما يبدأ أخذ لقطة من البيانات المهملة.
محو اللقطات
لإزالة جميع اللقطات، انقر على
محو جميع الملفات الشخصية:عرض اللقطات
لفحص لقطات من وجهات نظر مختلفة لأغراض مختلفة، حدد إحدى طرق العرض من القائمة المنسدلة في الأعلى:
عرض | المحتوى | الغرض |
---|---|---|
ملخّص | الكائنات التي تم تجميعها حسب أسماء الدالة الإنشائية. | ويمكنك استخدامه للبحث عن العناصر واستخدامها للذاكرة حسب النوع. هذا الخيار مفيد لتتبُّع تسريبات نموذج العناصر في المستند (DOM). |
المقارنة | الاختلافات بين لقطاتَين | استخدِمه لمقارنة صورتَين (أو أكثر) قبل إجراء عملية وبعده. تأكَّد من توفُّر تسرُّب للذاكرة وسبب حدوثه من خلال فحص الدلتا في الذاكرة الخالية من الرموز وعدد المراجع. |
الاحتواء | محتويات الحِزم | يوفر عرضًا أفضل لبنية الكائن، ويساعد في تحليل العناصر المشار إليها في مساحة الاسم العامة (النافذة) لمعرفة العناصر التي تحافظ عليها. ويمكنك استخدامه لتحليل حالات الإغلاق والتعمق في العناصر عند مستوى منخفض. |
الإحصاءات | رسم بياني دائري لتخصيص الذاكرة | يمكنك الاطّلاع على الأحجام الفعلية لأجزاء الذاكرة المخصّصة للرموز البرمجية والسلاسل وصفائف JavaScript والصفائف المكتوبة وعناصر النظام. |
العرض الملخّص
في البداية، يتم فتح لقطة لأجزاء من الذاكرة في عرض الملخّص الذي يسرد المنشئات في عمود. يمكنك توسيع الدالة الإنشائية للاطلاع على الكائنات التي أنشأت مثيلاً لها.
لفلترة وظائف الإنشاء غير ذات الصلة، اكتب اسمًا تريد فحصه في فلتر الصف في أعلى عرض الملخّص.
تشير الأرقام بجوار أسماء الدالة الإنشائية إلى العدد الإجمالي للكائنات التي تم إنشاؤها باستخدام الدالة الإنشائية. تعرِض طريقة عرض الملخّص أيضًا الأعمدة التالية:
- تعرض المسافة المسافة إلى الجذر باستخدام أقصر مسار بسيط بين العُقد.
- تعرِض سمة الحجم البسيط مجموع الأحجام البسيطة لجميع العناصر التي أنشأها أسلوب إنشاء معيّن. الحجم السطحي هو حجم الذاكرة التي يحتفظ بها الكائن نفسه. بشكل عام، الصفائف والسلاسل لها أحجام أكبر سطحية. راجِع أيضًا أحجام العناصر.
- يعرض الحجم الذي تم الاحتفاظ به الحد الأقصى للحجم الذي تم الاحتفاظ به بين مجموعة العناصر نفسها. الحجم المحتفظ به هو حجم الذاكرة التي يمكنك تحريرها عن طريق حذف كائن وجعل العناصر التابعة له لم تعد قابلة للوصول. راجِع أيضًا أحجام العناصر.
عند توسيع إحدى الدوال الإنشائية، تعرِض لك طريقة عرض الملخّص جميع مثيلاتها. يحصل كل مثيل على تقسيم لأحجامه السطحية والتي تم الاحتفاظ بها في الأعمدة المقابلة. الرقم بعد الحرف @
هو المعرّف الفريد للعنصر. يتيح لك ذلك مقارنة لقطات الذاكرة المؤقتة على أساس كل عنصر.
فلاتر طريقة الإنشاء
يتيح لك عرض الملخص فلترة الصيغ بناءً على الحالات الشائعة لاستخدام الذاكرة غير الفعّال.
لاستخدام هذه الفلاتر، حدد أحد الخيارات التالية من القائمة المنسدلة في أقصى اليسار في شريط الإجراءات:
- جميع الكائنات: جميع الكائنات التي التقطتها اللقطة الحالية يتم ضبطه تلقائيًا.
- العناصر التي تم تخصيصها قبل اللقطة 1: عناصر تم إنشاؤها وبقيت في الذاكرة قبل أخذ اللقطة الأولى.
- العناصر التي تم تخصيصها بين اللمحة 1 واللقطات 2: يمكنك الاطّلاع على الفرق بين العناصر بين أحدث لقطة واللقطة السابقة. تضيف كل لقطة جديدة جزءًا من هذا الفلتر إلى القائمة المنسدلة.
- السلاسل المكرّرة: قيم السلسلة التي تم تخزينها عدة مرات في الذاكرة.
- العناصر التي يتم الاحتفاظ بها من خلال عُقد منفصلة: يشير ذلك إلى العناصر التي تظلّ صالحة لأنّ عقدة DOM المنفصلة تشير إليها.
- العناصر التي تحتفظ بها "وحدة تحكُّم أدوات مطوّري البرامج": العناصر التي يتم الاحتفاظ بها في الذاكرة بسبب تقييمها أو التفاعل معها من خلال وحدة تحكُّم "أدوات مطوّري البرامج".
إدخالات خاصة في "الملخّص"
بالإضافة إلى التجميع حسب الدوال الإنشائية، تعمل طريقة عرض الملخّص أيضًا على تجميع الكائنات حسب:
- الدوالّ المدمَجة، مثل
Array
أوObject
- عناصر HTML مجمّعة حسب علاماتها، مثل
<div>
و<a>
و<img>
وغيرها - الدوال التي حددتها في التعليمة البرمجية.
- الفئات الخاصة التي لا تستند إلى الدوال الإنشائية.
(array)
تتضمّن هذه الفئة العديد من الكائنات الداخلية الشبيهة بالمصفوفة والتي لا تتوافق مباشرةً مع الكائنات المرئية في JavaScript.
على سبيل المثال، يتم تخزين محتوى كائنات Array
في JavaScript في كائن داخلي ثانوي يُسمّى (object elements)[]
لتسهيل تغيير الحجم. وبالمثل، يتم غالبًا تخزين السمات المحدّدة في عناصر JavaScript في كائنات داخلية ثانوية تُسمّى (object properties)[]
ومدرَجة أيضًا في الفئة (array)
.
(compiled code)
تتضمن هذه الفئة بيانات داخلية يحتاجها V8 من أجل تنفيذ الوظائف المحدّدة باستخدام JavaScript أو WebAssembly. يمكن تمثيل كل دالة بعدة طرق، من الصغيرة والبطيئة إلى الكبيرة والسريعة.
يدير V8 استخدام الذاكرة في هذه الفئة تلقائيًا. إذا تم تشغيل دالة عدة مرات، يستخدم V8 المزيد من الذاكرة لهذه الدالة حتى يمكن تشغيلها بشكل أسرع. إذا لم يتم تشغيل دالة منذ فترة، قد يُمحِّى V8 البيانات الداخلية لهذه الدالة.
(concatenated string)
عندما يُدمِج V8 سلسلةَين، مثلًا باستخدام عامل التشغيل +
في JavaScript، قد يختار تمثيل النتيجة داخليًا على أنّها "سلسلة متسلسلة"، والتي تُعرف أيضًا باسم بنية بيانات Rope.
بدلاً من نسخ جميع أحرف السلسلتَين المصدرَين إلى سلسلة جديدة، يخصِّص V8 عنصرًا صغيرًا يحتوي على حقلَين داخليَين باسم first
وsecond
، ويشيران إلى سلسلتَي المصدر. ويتيح ذلك لـ V8 توفير الوقت والذاكرة. من منظور رمز JavaScript، هذه مجرد سلاسل عادية، وتعمل مثل أي سلسلة أخرى.
InternalNode
تمثّل هذه الفئة العناصر المخصّصة خارج المحرِّك V8، مثل كائنات C++ المحدَّدة باستخدام Blink.
للاطّلاع على أسماء فئات C++ ، استخدِم Chrome for Testing واتّبِع ما يلي:
- افتح "أدوات مطوري البرامج" وفعِّل الإعدادات >. التجارب > إظهار خيار لعرض العناصر الداخلية في لقطات لأجزاء من الذاكرة.
- افتح لوحة الذاكرة، واختَر لقطة ذاكرة عشوائية، فعِّل عرض البيانات الداخلية (بما في ذلك تفاصيل إضافية خاصة بعملية التنفيذ).
- أعِد تنفيذ الخطوات التي أدّت إلى احتفاظ
InternalNode
بالكثير من الذاكرة. - تسجيل لقطة لأجزاء من الذاكرة في هذه اللقطة، تحتوي العناصر على أسماء فئة 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.
تُظهِر طريقة العرض مقارنة الفرق بين لقطتَين. عند توسيع إجمالي تظهر مثيلات العناصر التي تم إدخالها وتلك التي تمت إضافتها وحذفها:
عرض الاحتواء
عرض الاحتواء هو "منظور من أعلى" لبنية كائنات التطبيق. يتيح لك هذا الإجراء الاطّلاع على الدوالّ المغلقة، وملاحظة العناصر الداخلية لوحدة التحكّم في الذاكرة التي تشكّل معًا عناصر JavaScript، ومعرفة مقدار الذاكرة التي يستخدمها تطبيقك على مستوى منخفض جدًا.
يوفّر العرض عدة نقاط دخول:
- كائنات DOMWindow: كائنات عامة لرمز JavaScript.
- جذور GC: جذور جمع القمامة التي يستخدمها برنامج جمع القمامة في الجهاز الظاهري يمكن أن تتألف جذور تجميع البيانات المهملة من خرائط كائنات مضمّنة وجداول الرموز وحِزم سلاسل الأجهزة الافتراضية وذاكرات التخزين المؤقت للتجميع ونطاقات المقبض وأسماء المؤشرات العامة.
- العناصر المدمجة: كائنات المتصفح "تم دفعها" داخل جهاز JavaScript الافتراضي للسماح بالتشغيل الآلي، على سبيل المثال، عُقد DOM وقواعد CSS.
قسم "أدوات الاحتفاظ باللقطات"
يعرض قسم عمليات الاحتفاظ بالبيانات في أسفل لوحة الذاكرة عناصر تشير إلى العنصر الذي تم اختياره في طريقة العرض. تعدّل لوحة الذاكرة قسم الاحتفاظ بالبيانات عند اختيار عناصر مختلفة في أي من طرق العرض باستثناء الإحصاءات.
في هذا المثال، تحتفظ السمة x
لمثيل Item
بالسلسلة المحدّدة.
تجاهُل عمليات الاحتفاظ بالبيانات
يمكنك إخفاء عمليات الاحتفاظ بالبيانات إذا كانت هناك أي عناصر أخرى تحتفظ بالعنصر المحدد. باستخدام هذا الخيار، لن تحتاج إلى إزالة هذا العنصر الحافظ أولاً من الرمز البرمجي ثم إعادة التقاط لقطة ذاكرة عشوائية.
لإخفاء عملية احتفاظ، انقر بزر الماوس الأيمن ثم اختَر تجاهل عملية الاحتفاظ هذه. يتم وضع علامة ignored
على المبالغ المحجوزة في الحساب الدائم والتي تم تجاهلها في عمود المسافة. لإيقاف تجاهل جميع عمليات الاحتفاظ بالبيانات، انقر على استعادة عمليات الاحتفاظ التي تم تجاهلها في شريط الإجراءات أعلى الشاشة.
البحث عن عنصر معيّن
للعثور على عنصر في الذاكرة المجمّعة، يمكنك البحث باستخدام 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
وهي عنصر محفّز للتجميع التدريجي.