مصطلحات الذاكرة

ميجين كيرني
ميجين كيرني

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

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

أحجام العناصر

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

تمثيل مرئي للذاكرة

يمكن أن يحتفظ الكائن بالذاكرة بطريقتين:

  • مباشرةً من خلال العنصر نفسه
  • وذلك من خلال الاحتفاظ بمَراجع لأشياء أخرى، وبالتالي منع التخلص من هذه الأجسام تلقائيًا بواسطة أدوات تجميع النفايات (باختصار GC).

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

حجم ضحل وحجم محتفظ به

حجم صغير

هذا هو حجم الذاكرة التي يحتفظ بها الكائن نفسه.

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

ذاكرة العارض هي كامل ذاكرة العملية التي يتم فيها عرض الصفحة التي تم فحصها: الذاكرة الأصلية + ذاكرة كومة الذاكرة المؤقتة ل JavaScript للصفحة + ذاكرة كومة الذاكرة المؤقتة ل JavaScript لجميع العاملين المخصصين الذين تم بدء تشغيلهم من خلال الصفحة. ومع ذلك، يمكن أن يحتفظ الكائن الصغير بحجم كبير من الذاكرة بشكل غير مباشر، وذلك من خلال منع التخلص من الكائنات الأخرى عن طريق عملية التجميع التلقائي للبيانات المهملة.

الحجم المحتفظ به

هذا هو حجم الذاكرة التي يتم تحريرها بمجرد حذف الكائن نفسه مع العناصر التابعة له التي تعذّر الوصول إليها من جذور تجميع البيانات المهملة.

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

هناك الكثير من جذور تجميع البيانات المهملة الداخلية التي لا تهم المستخدمين غالبًا. من منظور التطبيقات، توجد الأنواع التالية من الجذور:

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

يبدأ الرسم البياني للذاكرة بجذر قد يكون الكائن window للمتصفّح أو كائن Global لوحدة Node.js. ولا يمكنك التحكّم في كيفية تجميع هذا العنصر الجذر.

لا يمكن التحكّم في الكائن الجذر.

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

عناصر تحافظ على الشجرة

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

  • يتم تصنيف العُقد (أو الكائنات) باستخدام اسم دالة الإنشاء التي تم استخدامها لإنشائها.
  • يتم تصنيف الحواف باستخدام أسماء المواقع.

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

المسافة من الجذر

دومينتورز

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

في الرسم البياني أدناه:

  • تهيمن العقدة 1 على العقدة 2
  • تهيمن العقدة 2 على العُقد 3 و4 و6
  • تهيمن العقدة 3 على العقدة 5
  • تهيمن العقدة 5 على العقدة 8
  • تهيمن العقدة 6 على العقدة 7

بنية شجرة السائدة

في المثال أدناه، العقدة #3 هي السائدة على #10، ولكن #7 تقع أيضًا في كل مسار بسيط من تجميع البيانات المهملة إلى #10. وبالتالي، يصبح الكائن B هو السائد للكائن A إذا كان B موجودًا في كل مسار بسيط من الجذر إلى الكائن A.

صورة توضيحية لقاعدة مهيمنة متحركة

تفاصيل V8

عند تحليل الذاكرة، من المفيد أن تفهم سبب ظهور لقطات كومة الذاكرة المؤقتة بطريقة معيّنة. يصف هذا القسم بعض المواضيع المتعلّقة بالذاكرة والمناظرة تحديدًا للجهاز الافتراضي V8 JavaScript (الجهاز الافتراضي (V8) أو الجهاز الافتراضي (VM)).

تمثيل كائن JavaScript

هناك ثلاثة أنواع أساسية:

  • أرقام (مثلاً (3.14159.).
  • قيم منطقية (صحيح أو خطأ)
  • السلاسل (مثل "فيرنر هايزنبرغ")

ولا يمكن أن تشير إلى قيم أخرى وتكون دائمًا أوراقًا أو عُقدًا منتهية.

يمكن تخزين الأرقام بالتنسيق التالي:

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

يمكن تخزين السلاسل في:

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

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

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

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

على سبيل المثال، في حال إجراء تسلسل لـ a وb، ستحصل على سلسلة (a، b) تمثل نتيجة الترابط. إذا ربطت لاحقًا d بهذه النتيجة، ستحصل على سلسلة سلبية أخرى ((a، b)، d).

الصفيفات - المصفوفة هي كائن يحتوي على مفاتيح رقمية. وتُستخدم على نطاق واسع في جهاز V8 الافتراضي لتخزين كميات كبيرة من البيانات. يتم نسخ مجموعات أزواج المفتاح/القيمة المستخدمة مثل القواميس احتياطيًا بواسطة مصفوفات.

يمكن أن يكون كائن JavaScript النموذجي أحد نوعَي المصفوفات المستخدَمة للتخزين:

  • والخصائص المسماة
  • العناصر الرقمية

في الحالات التي يتوفر فيها عدد قليل جدًا من الخصائص، يمكن تخزينها داخليًا في كائن JavaScript نفسه.

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

مجموعات الكائنات

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

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