إدارة ذاكرة تطبيقك

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

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

مراقبة استخدام الذاكرة والذاكرة المتاحة

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

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

تحرير الذاكرة استجابةً للأحداث

يمكن لنظام Android استعادة الذاكرة من تطبيقك أو إيقاف التطبيق تمامًا إذا لزم الأمر لإخلاء بعض الذاكرة للمهام الهامة، كما هو موضح في نظرة عامة على إدارة الذاكرة لمزيد من المساعدة تحقيق التوازن بين ذاكرة النظام وتجنب حاجة النظام لإيقاف عملية التطبيق، يمكنك تنفيذ الـ ComponentCallbacks2 واحدة في Activity صفًا. تم توفير onTrimMemory() تُعلِم طريقة معاودة الاتصال تطبيقك بالأحداث المتعلقة بدورة الحياة أو الذاكرة التي تقدم أن يقلل تطبيقك طوعًا من استخدامه للذاكرة. قد يؤدي تحرير الذاكرة إلى تقليل احتمالية إغلاق تطبيقك من خلال أداة إغلاق التطبيقات بسبب انخفاض مساحة الذاكرة.

يمكنك تنفيذ معاودة الاتصال onTrimMemory() للاستجابة إلى طلبات مختلفة متعلقة بالذاكرة الأحداث، كما هو موضح في المثال التالي:

Kotlin

import android.content.ComponentCallbacks2
// Other import statements.

class MainActivity : AppCompatActivity(), ComponentCallbacks2 {

    // Other activity code.

    /**
     * Release memory when the UI becomes hidden or when system resources become low.
     * @param level the memory-related event that is raised.
     */
    override fun onTrimMemory(level: Int) {

        if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
            // Release memory related to UI elements, such as bitmap caches.
        }

        if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
            // Release memory related to background processing, such as by
            // closing a database connection.
        }
    }
}

Java

import android.content.ComponentCallbacks2;
// Other import statements.

public class MainActivity extends AppCompatActivity
    implements ComponentCallbacks2 {

    // Other activity code.

    /**
     * Release memory when the UI becomes hidden or when system resources become low.
     * @param level the memory-related event that is raised.
     */
    public void onTrimMemory(int level) {

        if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
            // Release memory related to UI elements, such as bitmap caches.
        }

        if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
            // Release memory related to background processing, such as by
            // closing a database connection.
        }
    }
}

التحقق من مقدار الذاكرة التي تحتاجها

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

لتجنب نفاد الذاكرة، يمكنك الاستعلام عن النظام لتحديد مقدار مساحة كومة الذاكرة متوفّرة على الجهاز الحالي يمكنك الاستعلام من النظام عن هذا الرقم من خلال استدعاء getMemoryInfo() ينتج عن ذلك ActivityManager.MemoryInfo يقدّم هذا العنصر معلومات عن حالة ذاكرة الجهاز الحالية، بما في ذلك البيانات المتوفّرة الذاكرة وإجمالي الذاكرة وحد الذاكرة - مستوى الذاكرة الذي يبدأ عنده النظام وإيقاف العمليات. يعرِض عنصر ActivityManager.MemoryInfo أيضًا lowMemory، وهو قيمة منطقية بسيطة تُعلمك ما إذا كانت ذاكرة الجهاز منخفضة.

يوضح المثال التالي مقتطف الرمز كيفية استخدام طريقة getMemoryInfo() في تطبيقك.

Kotlin

fun doSomethingMemoryIntensive() {

    // Before doing something that requires a lot of memory,
    // check whether the device is in a low memory state.
    if (!getAvailableMemory().lowMemory) {
        // Do memory intensive work.
    }
}

// Get a MemoryInfo object for the device's current memory status.
private fun getAvailableMemory(): ActivityManager.MemoryInfo {
    val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    return ActivityManager.MemoryInfo().also { memoryInfo ->
        activityManager.getMemoryInfo(memoryInfo)
    }
}

Java

public void doSomethingMemoryIntensive() {

    // Before doing something that requires a lot of memory,
    // check whether the device is in a low memory state.
    ActivityManager.MemoryInfo memoryInfo = getAvailableMemory();

    if (!memoryInfo.lowMemory) {
        // Do memory intensive work.
    }
}

// Get a MemoryInfo object for the device's current memory status.
private ActivityManager.MemoryInfo getAvailableMemory() {
    ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    activityManager.getMemoryInfo(memoryInfo);
    return memoryInfo;
}

استخدام بُنى رموز برمجية فعّالة في الذاكرة

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

استخدام الخدمات باعتدال

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

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

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

استخدام حاويات البيانات المحسَّنة

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

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

يمكنك متى شئت التبديل إلى صفائف أولية للحصول على بنية بيانات بسيطة.

توخي الحذر بشأن التجريدات في الرموز البرمجية

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

استخدام النماذج الأوّلية البسيطة للبيانات المتسلسلة

البروتوكول الموارد الاحتياطية (protobufs) هي آلية محايدة لغة ومحايدة للمنصة وقابلة للتوسُّع مصمَّمة من قِبل Google لإنشاء تسلسل للبيانات المنظَّمة، وهو يشبه تنسيق XML، لكنّه أصغر وأسرع وأبسط. في حال حذف فإنك تستخدم نماذج أوّلية لبياناتك، وتستخدم دائمًا نماذج lite في التعليمة البرمجية من جانب العميل. عادية تنشئ النماذج الأوّلية رمزًا مطوّلاً للغاية، ما قد يتسبب في حدوث العديد من المشاكل في تطبيقك، مثل زيادة استخدام ذاكرة الوصول العشوائي، وزيادة كبيرة في حجم APK، وبطء التنفيذ.

لمزيد من المعلومات، يُرجى الاطّلاع على Protobuf readme.

تجنُّب اضطرابات الذاكرة

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

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

على سبيل المثال، يمكنك تخصيص عناصر مؤقتة متعددة ضمن حلقة for. أو يمكنك إنشاء Paint أو جديد Bitmap عنصرًا داخل onDraw() طريقة العرض. وفي كلتا الحالتين، ينشئ التطبيق الكثير من العناصر بسرعة وبحجم كبير. هذه بسرعة استهلاك كل الذاكرة المتاحة لدى الجيل الناشئ، مما يؤدي إلى إجبار المستخدمين على جمع البيانات وقوع الحدث.

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

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

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

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

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

إزالة الموارد والمكتبات ذات الاستهلاك الكثيف للذاكرة

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

تقليل الحجم الإجمالي لحِزم APK

يمكنك تقليل استخدام تطبيقك للذاكرة بشكل كبير عن طريق تقليل الحجم الإجمالي للتطبيق. يمكن أن يساهم حجم الصور النقطية والموارد وإطارات الرسوم المتحركة ومكتبات الجهات الخارجية في زيادة حجم لتطبيقك. ويوفر "استوديو Android" وحزمة تطوير البرامج (SDK) لنظام التشغيل Android أدوات متعددة للمساعدة في تقليل حجم مواردك وتبعياتك الخارجية. وتدعم هذه الأدوات طرقًا حديثة لتقليص التعليمات البرمجية، مثل تجميع R8:

لمزيد من المعلومات عن تقليل الحجم الكلي لتطبيقك، يُرجى الاطّلاع على مقالة تقليل حجم تطبيقك.

استخدام Hilt أو Dagger 2 لحقن التبعية

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

إذا كنت تنوي استخدام إطار عمل إدخال التبعية في تطبيقك، ننصحك باستخدام وظيفة أو Dagger: Hilt هي حقن تبعية. لـ Android تعمل أعلى تطبيق Dagger. لا يستخدم تطبيق Dagger ميزة الانعكاس لفحص صورة الرمز. يمكنك استخدام تنفيذ وقت التجميع الثابت في تطبيقات Android باستخدام أداة Dagger بدون داعٍ. وقت التشغيل أو استخدام الذاكرة.

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

توخ الحذر بشأن استخدام المكتبات الخارجية

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

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

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

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