التقاط نَسْخ للذاكرة

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

تصف هذه الصفحة الأدوات التي يوفّرها "استوديو Android" لجمع لقطات لأجزاء من الذاكرة وتحليلها. بدلاً من ذلك، يمكنك فحص ذاكرة تطبيقك من سطر الأوامر باستخدام dumpsys والاطّلاع أيضًا على أحداث جمع البيانات المُهمَلة (GC) في Logcat.

أهمية تحديد خصائص ذاكرة تطبيقك

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

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

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

نظرة عامة على لقطات أجزاء من الذاكرة

لتسجيل لقطة لأجزاء من الذاكرة، اختَر مهمة تحليل استخدام الذاكرة (لقطة لأجزاء من الذاكرة) (استخدِم أداة تحديد الأداء: تشغيل 'التطبيق' كإصدار قابل لتصحيح الأخطاء (بيانات كاملة)) لتسجيل لقطة لأجزاء من الذاكرة. أثناء تسجيل لقطة لأجزاء من الذاكرة، قد يزداد حجم ذاكرة Java مؤقتًا. هذا أمر طبيعي لأنّ لقطة أجزاء من الذاكرة تحدث في العملية نفسها التي يستخدمها تطبيقك وتتطلب بعض الذاكرة لجمع البيانات. بعد تسجيل لقطة لأجزاء من الذاكرة، ستظهر لك ما يلي:

عرض "لقطة لأجزاء من الذاكرة" في "أداة تحديد الأداء" في "استوديو Android"

تعرض قائمة الفئات المعلومات التالية:

  • عمليات التخصيص: عدد عمليات التخصيص في الذاكرة الرئيسية.
  • الحجم الأصلي: إجمالي حجم الذاكرة الأصلية التي يستخدمها نوع الكائن هذا (بال بايت). ستظهر لك الذاكرة هنا لبعض الكائنات التي تم تخصيصها في Java لأنّ Android يستخدم الذاكرة الأصلية لبعض فئات إطار العمل، مثل Bitmap.

  • الحجم السطحي: إجمالي حجم ذاكرة Java التي يستخدمها نوع الكائن هذا (بالبايت).

  • الحجم المحتفظ به: إجمالي حجم الذاكرة المحتفظ بها بسبب جميع مثيلات هذه الفئة (بالبايت).

استخدِم قائمة الذاكرة الرئيسية للفلترة حسب ذاكرة رئيسية معيّنة:

  • ذاكرة التطبيق الرئيسية (تلقائي): الذاكرة الرئيسية التي يخصّص تطبيقك الذاكرة عليها.
  • Image heap: صورة التشغيل للنظام، التي تحتوي على الفئات التي يتم تحميلها مسبقًا أثناء وقت التشغيل. لا يتم نقل عمليات التخصيص هنا أو إزالتها.
  • ذاكرة Zygote الرئيسية: ذاكرة النسخ عند الكتابة التي يتم فيها إنشاء عملية التطبيق من خلال تفرّعها من نظام Android.

استخدِم القائمة المنسدلة "الترتيب" لاختيار كيفية ترتيب عمليات التخصيص:

  • الترتيب حسب الفئة (تلقائي): يجمّع جميع عمليات التخصيص استنادًا إلى اسم الفئة.
  • الترتيب حسب الحزمة: يجمّع جميع عمليات التخصيص استنادًا إلى اسم الحزمة.

استخدِم القائمة المنسدلة "الفئة" للفلترة حسب مجموعات الفئات:

  • جميع الفئات (تلقائي): يعرض جميع الفئات، بما في ذلك الفئات من المكتبات والتبعيات.
  • عرض تسرّبات الأنشطة/القصاصات: يعرض الفئات التي تسبّب تسرّبات الذاكرة.
  • عرض فئات المشروع: يعرض الفئات التي يحدّدها مشروعك فقط.

انقر على اسم فئة لفتح لوحة المثيل. يتضمّن كل مثيل مدرَج ما يلي:

  • العمق: أقصر عدد من عمليات الانتقال من أي جذر لجمع البيانات غير الضرورية إلى المثيل المحدّد.
  • الحجم الأصلي: حجم هذا المثيل في الذاكرة الأصلية. لا يظهر هذا العمود إلا في Android 7.0 والإصدارات الأحدث.
  • الحجم السطحي: حجم هذا المثيل في ذاكرة Java.
  • الحجم المحتفظ به: حجم الذاكرة التي يتحكّم بها هذا المثيل (وفقًا لـ شجرة المتحكّم).

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

  • الحقول: يعرض جميع الحقول في هذا المثيل.
  • المراجع: يعرض كل مرجع للكائن المميّز في علامة التبويب المثيل.
تعرض النوافذ المثيلات والحقول والمراجع في نافذة أداة "لقطة لأجزاء من الذاكرة".

رصد الصور النقطية المكرّرة

يمكنك أيضًا رصد الصور النقطية الزائدة في عرض "لقطة لأجزاء من الذاكرة" بدءًا من استوديو Android Narwhal 4.

إليك كيفية العثور عليها:

  1. افتح علامة التبويب "أداة تحديد الأداء" في "استوديو Android".
  2. انقر على لقطة لأجزاء من الذاكرة (أو تحليل استخدام الذاكرة) وانقر على "تسجيل" لأخذ لقطة لحالة الذاكرة الحالية في تطبيقك.
  3. ابحث في نتائج التحليل عن مثلث التحذير الأصفر ⚠️، الذي يستخدمه "استوديو Android" لوضع علامة على الصور النقطية المكرّرة التي يتم تخزينها عدة مرات.
    • بدلاً من ذلك، انتقِل إلى رأس أداة تحديد الأداء، واختَر الفلترة حسب: واختَر الإعداد الصور النقطية المكرّرة.
  4. انقر على أي إدخال تم وضع علامة عليه لفتح لوحة معاينة الصورة النقطية ، ما يتيح لك معرفة الصورة التي يتم تكرارها بالضبط.
  5. استخدِم هذا التأكيد المرئي لتتبُّع منطق التحميل الزائد في الرمز وتنفيذ استراتيجية أفضل للتخزين المؤقت.
ابحث عن الصور النقطية المكرّرة باستخدام مثلث التحذير الأصفر ⚠️.

العثور على تسرّبات الذاكرة

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

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

  • المراجع الطويلة الأمد إلى Activity أو Context التي يمكن أن تسرّب الرسم البياني لتركيبة Compose المستضافة (مثل ComposeView والعناصر الفرعية القابلة للإنشاء).
  • تسرّب كائنات حالة Jetpack Compose (MutableState) أو عناصر الاحتفاظ بالحالة أو تعبيرات لامدا التي تلتقط Context.
  • عدم تنظيف المستمعين أو المراقبين في كتلة onDispose من DisposableEffect.
  • الفئات الداخلية غير الثابتة، مثل Runnable، التي يمكن أن تحتوي على مثيل Activity.
  • ذاكرات التخزين المؤقت التي تحتفظ بالكائنات لفترة أطول من اللازم.

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

إحداث تسرّبات الذاكرة للاختبار

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

يمكنك أيضًا إحداث تسرّب الذاكرة بإحدى الطرق التالية:

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

تصدير تسجيل لقطة لأجزاء من الذاكرة واستيراده

يمكنك تصدير ملف لقطة لأجزاء من الذاكرة واستيراده من علامة التبويب التسجيلات السابقة في أداة تحديد الأداء. يحفظ "استوديو Android" التسجيل كملف ‎.hprof.

بدلاً من ذلك، لاستخدام محلّل ملفات .hprof مختلف، مثل jhat، عليك تحويل ملف .hprof من تنسيق Android إلى تنسيق ملف .hprof Java SE. لتحويل تنسيق الملف، استخدِم أداة hprof-conv المتوفّرة في الدليل {android_sdk}/platform-tools/. شغِّل الأمر hprof-conv باستخدام وسيطتَين: اسم ملف ‎.hprof الأصلي والموقع الذي تريد كتابة ملف ‎.hprof المحوَّل فيه، بما في ذلك اسم ملف ‎.hprof الجديد. على سبيل المثال:

hprof-conv heap-original.hprof heap-converted.hprof

مراجع إضافية