أفضل ممارسات إدارة الذاكرة

يفترض هذا المستند أنّك اتّبعت إرشادات أفضل الممارسات لتطبيقات Android في ما يتعلّق بإدارة الذاكرة، مثل إدارة ذاكرة تطبيقك.

مقدمة

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

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

قبل التواصل مع فريق الدعم

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

منع تسرُّب الذاكرة

اتّبِع أفضل الممارسات التالية للمساعدة في تجنُّب بعض الأسباب الأكثر شيوعًا لتسرُّب الذاكرة في الرموز البرمجية التي تستخدم حِزم تطوير البرامج (SDK) من Google.

أفضل الممارسات لتطبيقات Android

تأكَّد من أنّك نفّذت كل ما يلي في تطبيق Android:

  1. إلغاء حجز الموارد غير المستخدَمة
  2. إلغاء تسجيل أدوات معالجة الأحداث عندما لا يعود هناك حاجة إليها
  3. إلغاء المهام عند عدم الحاجة إليها
  4. توجيه طرق دورة الحياة إلى الأمام لتحرير الموارد
  5. استخدام أحدث إصدارات حِزم تطوير البرامج (SDK)
  6. تجنَّب حظر سلسلة التعليمات الرئيسية أثناء عملية التهيئة لمنع حدوث أخطاء ANR.

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

إلغاء حجز الموارد غير المُستخدَمة

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

إصدار مراجع GoogleMap قديمة في GeoSDKs

من الأخطاء الشائعة أنّ GoogleMap يمكن أن يتسبّب في تسرُّب الذاكرة إذا تم تخزينه مؤقتًا باستخدام NavigationView أو MapView. تتضمّن GoogleMap علاقة واحد إلى واحد مع NavigationView أو MapView التي يتم استردادها منها. يجب التأكّد من عدم تخزين GoogleMap مؤقتًا، أو من تحرير المرجع عند استدعاء NavigationView#onDestroy أو MapView#onDestroy. في حال استخدام NavigationSupportFragment أو MapSupportFragment أو جزء خاص بك يضم هذه العروض، يجب تحرير المرجع في Fragment#onDestroyView.

class NavFragment : SupportNavigationFragment() {

  var googleMap: GoogleMap?

  override fun onCreateView(
    inflater: LayoutInflater,
    parent: ViewGroup?,
    savedInstanceState: Bundle?,
  ): View  {
    super.onCreateView(inflater,parent,savedInstanceState)
    getMapAsync{map -> googleMap = map}
  }

  override fun onDestroyView() {
    googleMap = null
  }
}

إلغاء تسجيل المستمعين عند عدم الحاجة إليهم

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

على سبيل المثال، إذا كان تطبيقك يستخدم حزمة تطوير البرامج (SDK) الخاصة بخدمة Navigation، وكان يستدعي أداة المعالجة التالية للاستماع إلى أحداث الوصول: addArrivalListener للاستماع إلى أحداث الوصول، يجب أن يستدعي أيضًا removeArrivalListener عندما لا يعود بحاجة إلى مراقبة أحداث الوصول.

var arrivalListener: Navigator.ArrivalListener? = null

fun registerNavigationListeners() {
  arrivalListener =
    Navigator.ArrivalListener {
      ...
    }
  navigator.addArrivalListener(arrivalListener)
}

override fun onDestroy() {
  navView.onDestroy()
  if (arrivalListener != null) {
    navigator.removeArrivalListener(arrivalListener)
  }

  ...
  super.onDestroy()
}

إلغاء المهام عند عدم الحاجة إليها

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

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

توجيه طرق دورة الحياة لإتاحة الموارد

إذا كان تطبيقك يستخدم حزمة تطوير البرامج (SDK) الخاصة بالتنقل أو الخرائط، احرص على تحرير الموارد من خلال إعادة توجيه طرق دورة الحياة (الموضّحة بالخط العريض) إلى navView. يمكنك إجراء ذلك باستخدام NavigationView في حزمة Navigation SDK أو MapView في حزمة Maps SDK أو Navigation SDK. يمكنك أيضًا استخدام SupportNavigationFragment أو SupportMapFragment بدلاً من استخدام NavigationView وMapView مباشرةً. تتعامل الأجزاء المتوافقة مع إعادة توجيه طرق دورة الحياة.

class NavViewActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...
    navView = ...
    navView.onCreate(savedInstanceState)
    ...
  }

  override fun onSaveInstanceState(savedInstanceState: Bundle) {
    super.onSaveInstanceState(savedInstanceState)
    navView.onSaveInstanceState(savedInstanceState)
  }

  override fun onTrimMemory(level: Int) {
    super.onTrimMemory(level)
    navView.onTrimMemory(level)
  }

  /* Same with
    override fun onStart()
    override fun onResume()
    override fun onPause()
    override fun onConfigurationChanged(...)
    override fun onStop()
    override fun onDestroy()
  */
}

استخدام أحدث إصدارات حِزم SDK

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

تجنُّب حظر سلسلة التعليمات الرئيسية أثناء عملية التهيئة لمنع حدوث أخطاء ANR

عندما يحظر تطبيق سلسلة التعليمات الرئيسية لفترة طويلة جدًا، يمكن أن يؤدي ذلك إلى حدوث خطأ "التطبيق لا يستجيب" (ANR). لمنع حدوث أخطاء ANR، يجب أن تكون طرق دورة الحياة، مثل onCreate()، بسيطة قدر الإمكان من خلال تأجيل المهام التي تستغرق وقتًا طويلاً أو تنفيذها في سلسلة تعليمات أخرى غير السلسلة الرئيسية.

لتجنُّب أخطاء ANR المرتبطة بإعداد حزمة SDK، اتّبِع الخطوات التالية:

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

تصحيح أخطاء تسرُّب الذاكرة

إذا استمر ظهور تسريبات الذاكرة بعد تنفيذ جميع الاقتراحات السارية الواردة سابقًا في هذا المستند، اتّبِع الخطوات التالية لتحديد المشاكل وحلّها.

قبل البدء، يجب أن تكون على دراية بكيفية إدارة Android للذاكرة. للحصول على معلومات، يُرجى قراءة نظرة عامة على إدارة الذاكرة في Android.

لتصحيح أخطاء تسريب الذاكرة، اتّبِع الخطوات التالية:

  1. أعِد عرض المشكلة. هذه الخطوة ضرورية لتصحيح الأخطاء.
  2. تحقَّق مما إذا كان استخدام الذاكرة متوقعًا. تأكَّد من أنّ الاستخدام المتزايد الذي يبدو أنّه تسريب ليس في الواقع مقدار الذاكرة المطلوب لتشغيل تطبيقك.
  3. تصحيح الأخطاء على مستوى عالٍ: تتوفّر العديد من الأدوات التي يمكنك استخدامها لتصحيح الأخطاء. تساعد ثلاث مجموعات أدوات مختلفة في تصحيح أخطاء الذاكرة في Android، وهي: "استوديو Android" وPerfetto وأدوات سطر الأوامر في Android Debug Bridge (adb).
  4. التحقّق من استخدام تطبيقك للذاكرة: احصل على لقطة لأجزاء من الذاكرة وتتبُّع التخصيص، ثم حلِّلهما.
  5. إصلاح تسربات الذاكرة

تتناول الأقسام التالية هذه الخطوات بالتفصيل.

الخطوة 1: إعادة عرض المشكلة

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

  • ما هي مجموعة الميزات التي يتم تفعيلها؟

  • ما هي التسلسلات المحدّدة لإجراءات المستخدم التي تؤدي إلى حدوث التسريب؟

    • هل حاولت تفعيل هذا التسلسل عدة مرات؟
  • ما هي حالات دورة الحياة التي مرّ بها التطبيق؟

    • هل جرّبت تكرارات متعددة من خلال حالات دورة الحياة المختلفة؟

تأكَّد من إمكانية إعادة إنشاء المشكلة في أحدث إصدار من حِزم SDK. يُحتمَل أنّه تم حلّ المشكلة في إصدار سابق.

الخطوة 2: التحقّق مما إذا كان استخدام الذاكرة للتطبيق متوقعًا

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

  • من المحتمل حدوث تسرُّب: يؤدي تفعيل السيناريو من خلال تكرارات متعددة إلى زيادة استخدام الذاكرة بمرور الوقت.

  • الاستخدام المتوقّع للذاكرة على الأرجح: تتم استعادة الذاكرة بعد إيقاف السيناريو.

  • الاستخدام المتوقّع للذاكرة: يزداد استخدام الذاكرة لفترة من الوقت ثم ينخفض تدريجيًا، وقد يرجع ذلك إلى ذاكرة تخزين مؤقت محدودة أو استخدام متوقّع آخر للذاكرة.

إذا كان سلوك التطبيق هو الاستخدام المتوقّع للذاكرة، يمكن حل المشكلة من خلال إدارة ذاكرة تطبيقك. للحصول على المساعدة، اطّلِع على إدارة ذاكرة تطبيقك.

الخطوة 3: تصحيح الأخطاء على مستوى عالٍ

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

أداة "محلّل الذاكرة" في "استوديو Android"

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

عدادات الذاكرة في Perfetto

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

واجهة مستخدم Perfetto

أدوات سطر الأوامر في Android Debug Bridge (adb)

تتوفّر معظم البيانات التي يمكنك تتبُّعها باستخدام Perfetto أيضًا كأداة adb سطر أوامر يمكنك طلبها مباشرةً. في ما يلي مثالان مهمّان:

  • تتيح لك أداة Meminfo الاطّلاع على معلومات مفصّلة عن الذاكرة في وقت معيّن.

  • تقدّم Procstats بعض الإحصاءات المجمّعة المهمة بمرور الوقت.

الإحصاء المهم الذي يجب الاطّلاع عليه هنا هو الحد الأقصى لاستهلاك الذاكرة الفعلية (maxRSS) الذي يتطلّبه التطبيق بمرور الوقت. قد لا تكون قيمة MaxPSS دقيقة. للحصول على طريقة لزيادة الدقة، اطّلِع على العلامة adb shell dumpsys procstats --help –start-testing.

تتبُّع التخصيص

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

الخطوة 4: التحقّق من استخدام تطبيقك للذاكرة باستخدام لقطة لأجزاء من الذاكرة

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

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

  1. التقاط لقطة لأجزاء من الذاكرة
  2. تحليل لقطة لأجزاء من الذاكرة للعثور على تسرُّبات الذاكرة
  3. إصلاح تسربات الذاكرة

لمعرفة التفاصيل، يُرجى الاطّلاع على الأقسام التالية.

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

لالتقاط لقطة لأجزاء من الذاكرة، يمكنك استخدام أداة Android Debug Bridge (adb) أو أداة محلّل الذاكرة في "استوديو Android".

استخدام adb لالتقاط لقطة لأجزاء من الذاكرة

لالتقاط لقطة لأجزاء من الذاكرة باستخدام adb، اتّبِع الخطوات التالية:

  1. وصِّل جهاز Android بجهاز الكمبيوتر.
  2. افتح موجه الأوامر وانتقِل إلى الدليل الذي توجد فيه أدوات adb.
  3. لالتقاط لقطة لأجزاء من الذاكرة، شغِّل الأمر التالي :

    adb shell am dumpheap my.app.name $PHONE_FILE_OUT

  4. لاسترداد لقطة لأجزاء من الذاكرة، نفِّذ الأمر التالي:

    adb pull $PHONE_FILE_OUT $LOCAL_FILE.

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

لالتقاط لقطة لأجزاء من الذاكرة باستخدام "محلّل الذاكرة" في "استوديو Android"، اتّبِع الخطوات الواردة في قسم التقاط لقطة لأجزاء من الذاكرة في صفحة Android.

تحليل لقطة لأجزاء من الذاكرة للعثور على تسرُّبات الذاكرة

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

  1. افتح مشروع Android في "استوديو Android".

  2. انقر على تنفيذ، ثمّ اختَر إعدادات تصحيح الأخطاء.

  3. افتح علامة التبويب Android Profiler.

  4. انقر على الذكريات.

  5. انقر على فتح لقطة لأجزاء من الذاكرة واختَر ملف لقطة لأجزاء من الذاكرة الذي أنشأته. يعرض أداة تحليل الذاكرة رسمًا بيانيًا لاستخدام تطبيقك للذاكرة.

  6. استخدِم الرسم البياني لتحليل لقطة لأجزاء من الذاكرة:

    • تحديد العناصر التي لم يعُد يتم استخدامها

    • تحديد العناصر التي تستهلك مقدارًا كبيرًا من الذاكرة

    • اطّلِع على مقدار الذاكرة التي يستخدمها كل عنصر.

  7. استخدِم هذه المعلومات لتحديد مصدر تسرُّب الذاكرة أو العثور عليه وحلّ المشكلة.

الخطوة 5: إصلاح تسربات الذاكرة

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

أدوات تصحيح الأخطاء الأخرى

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

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

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

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

تحديد عمليات تسرُّب الذاكرة باستخدام LeakCanary

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

كيفية الإبلاغ عن مشاكل في حِزم تطوير البرامج (SDK) من Google

إذا جرّبت الطرق الواردة في هذا المستند وكنت تشك في حدوث تسرّب للذاكرة في حِزم SDK، يُرجى التواصل مع فريق دعم العملاء وتزويده بأكبر قدر ممكن من المعلومات التالية:

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

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

  • في حال توقُّع حدوث تسرُّب للذاكرة الأصلية، شارِك ناتج تتبُّع عملية التخصيص من heapprofd.

  • تقرير خطأ تم إعداده بعد إعادة إنشاء حالة التسريب

  • تتبُّع تسلسل استدعاء الدوال البرمجية لأي أعطال متعلقة بالذاكرة

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