يعتمد نظام Android الأساسي على مبدأ أنّ الذاكرة الخالية هي ذاكرة مهدرة. ويحاول استخدام كل الذاكرة المتاحة في جميع الأوقات. على سبيل المثال، يحتفظ النظام بالتطبيقات في الذاكرة بعد إغلاقها ليتمكّن المستخدم من التبديل إليها بسرعة. لهذا السبب، غالبًا ما تعمل أجهزة Android مع ذاكرة خالية قليلة جدًا. تُعدّ إدارة الذاكرة أمرًا حيويًا لتخصيص الذاكرة بشكل صحيح بين عمليات النظام المهمة والعديد من تطبيقات المستخدمين.
تتناول هذه الصفحة أساسيات كيفية تخصيص Android للذاكرة للنظام وتطبيقات المستخدمين. كما توضّح كيفية تفاعل نظام التشغيل مع حالات انخفاض الذاكرة.
أنواع الذاكرة
تحتوي أجهزة Android على ثلاثة أنواع مختلفة من الذاكرة: ذاكرة الوصول العشوائي (RAM) وذاكرة zRAM ومساحة التخزين. يُرجى العِلم أنّ كلًا من وحدة المعالجة المركزية (CPU) ووحدة معالجة الرسومات (GPU) تصلان إلى ذاكرة الوصول العشوائي نفسها.
الشكل 1: أنواع الذاكرة: ذاكرة الوصول العشوائي (RAM) وذاكرة zRAM ومساحة التخزين
ذاكرة الوصول العشوائي (RAM) هي أسرع أنواع الذاكرة، ولكن حجمها محدود عادةً. تحتوي الأجهزة المتطورة عادةً على أكبر قدر من ذاكرة الوصول العشوائي.
ذاكرة zRAM هي قسم من ذاكرة الوصول العشوائي تُستخدم لمساحة الإبدال. يتم ضغط كل شيء عند وضعه في ذاكرة zRAM، ثم يتم فك ضغطه عند نسخه من ذاكرة zRAM. يزداد حجم هذا الجزء من ذاكرة الوصول العشوائي أو ينقص عند نقل الصفحات إلى ذاكرة zRAM أو إخراجها منها. يمكن لمصنّعي الأجهزة ضبط الحد الأقصى للحجم.
تحتوي مساحة التخزين على جميع البيانات الثابتة، مثل نظام الملفات ورمز الكائن المضمّن لجميع التطبيقات والمكتبات والمنصة. تتوفّر في مساحة التخزين سعة أكبر بكثير من النوعَين الآخرَين من الذاكرة. على Android، لا تُستخدم مساحة التخزين لمساحة الإبدال كما هو الحال في عمليات تنفيذ Linux الأخرى، لأنّ الكتابة المتكررة يمكن أن تؤدي إلى تآكل هذه الذاكرة وتقصير عمر وسيط التخزين.
صفحات الذاكرة
يتم تقسيم ذاكرة الوصول العشوائي إلى صفحات. عادةً ما يكون حجم كل صفحة 4 كيلوبايت من الذاكرة.
تُعتبر الصفحات إما خالية أو مستخدَمة. الصفحات الخالية هي ذاكرة وصول عشوائي غير مستخدَمة. الصفحات المستخدَمة هي ذاكرة وصول عشوائي يستخدمها النظام بنشاط، ويتم تجميعها في الفئات التالية:
- مخزّنة مؤقتًا: ذاكرة يتم الاحتفاظ بنسخة احتياطية منها في ملف على مساحة التخزين (على سبيل المثال، الرمز أو الملفات التي تم ربطها بالذاكرة) هناك نوعان من الذاكرة المخزّنة مؤقتًا:
- خاصة: مملوكة لعملية واحدة وغير مشترَكة
- نظيفة: نسخة غير معدَّلة من ملف على مساحة التخزين، ويمكن حذفها من خلال
kswapdلزيادة الذاكرة الخالية - غير نظيفة: نسخة معدَّلة من الملف على مساحة التخزين، ويمكن نقلها إلى ذاكرة zRAM أو ضغطها فيها من خلال
kswapdلزيادة الذاكرة الخالية
- نظيفة: نسخة غير معدَّلة من ملف على مساحة التخزين، ويمكن حذفها من خلال
- مشترَكة: مستخدَمة من خلال عمليات متعددة
- خاصة: مملوكة لعملية واحدة وغير مشترَكة
- مجهولة: ذاكرة لا يتم الاحتفاظ بنسخة احتياطية منها في ملف على مساحة التخزين (على سبيل المثال،
تم تخصيصها من خلال
mmap()مع ضبط العلامةMAP_ANONYMOUS)- غير نظيفة: يمكن نقلها إلى ذاكرة zRAM أو ضغطها فيها من خلال
kswapdلزيادة الذاكرة الخالية
- غير نظيفة: يمكن نقلها إلى ذاكرة zRAM أو ضغطها فيها من خلال
تختلف نسب الصفحات الخالية والمستخدَمة بمرور الوقت لأنّ النظام يدير ذاكرة الوصول العشوائي بنشاط. تُعدّ المفاهيم التي تم تقديمها في هذا القسم أساسية لإدارة حالات انخفاض الذاكرة. ويشرحها القسم التالي من هذا المستند بتفصيل أكبر.
إدارة حالات انخفاض الذاكرة
يتضمّن Android آليتَين رئيسيتَين للتعامل مع حالات انخفاض الذاكرة: برنامج kernel swap daemon وآلية إنهاء العمليات عند انخفاض الذاكرة.
برنامج kernel swap daemon
برنامج kernel swap daemon (kswapd) هو جزء من نواة Linux، ويحوّل الذاكرة المستخدَمة إلى ذاكرة خالية. يصبح البرنامج الخفي نشطًا عندما تنخفض الذاكرة الخالية على الجهاز. تحتفظ نواة Linux بحدَّين أدنى وأعلى للذاكرة الخالية.
عندما تنخفض الذاكرة الخالية عن الحد الأدنى، يبدأ برنامج kswapd في استعادة الذاكرة. وبمجرد أن تصل الذاكرة الخالية إلى الحد الأعلى، يتوقف برنامج kswapd عن استعادة الذاكرة.
يمكن لبرنامج kswapd استعادة الصفحات النظيفة عن طريق حذفها لأنّه يتم الاحتفاظ بنسخة احتياطية منها في مساحة التخزين ولم يتم تعديلها. إذا حاولت إحدى العمليات الوصول إلى صفحة نظيفة تم حذفها، ينسخ النظام الصفحة من مساحة التخزين إلى ذاكرة الوصول العشوائي. تُعرف هذه العملية باسم التقسيم إلى صفحات عند الطلب.
الشكل 2: صفحة نظيفة يتم الاحتفاظ بنسخة احتياطية منها في مساحة التخزين، وتم حذفها
يمكن لبرنامج kswapd نقل الصفحات غير النظيفة الخاصة المخزّنة مؤقتًا والصفحات غير النظيفة المجهولة إلى ذاكرة zRAM، حيث يتم ضغطها. يؤدي ذلك إلى إخلاء الذاكرة المتاحة في ذاكرة الوصول العشوائي (الصفحات الخالية). إذا حاولت إحدى العمليات الوصول إلى صفحة معدّلة في ذاكرة zRAM، يتم فك ضغط الصفحة ونقلها مرة أخرى إلى ذاكرة الوصول العشوائي (RAM). إذا تم إنهاء العملية المرتبطة بصفحة مضغوطة، يتم حذف الصفحة من ذاكرة zRAM.
إذا انخفض مقدار الذاكرة الخالية عن حد معيّن، يبدأ النظام في إنهاء العمليات.
الشكل 3: صفحة معدّلة تم نقلها إلى ذاكرة zRAM وضغطها
آلية إنهاء العمليات عند انخفاض الذاكرة
في كثير من الأحيان، لا يمكن لبرنامج kswapd إخلاء ذاكرة كافية للنظام. في هذه الحالة، يستخدم النظام
onTrimMemory()
لإشعار أحد التطبيقات بأنّ الذاكرة تنخفض وأنّه يجب تقليل عمليات التخصيص. إذا لم يكن ذلك كافيًا، تبدأ النواة في إنهاء العمليات لإخلاء الذاكرة. ويستخدم النظام آلية إنهاء العمليات عند انخفاض الذاكرة (LMK) للقيام بذلك.
لتحديد العملية التي سيتم إنهاؤها، تستخدم آلية LMK نتيجة "نفاد الذاكرة" تُسمى
oom_adj_score
لترتيب العمليات قيد التشغيل حسب الأولوية. يتم إنهاء العمليات التي حصلت على نتيجة عالية أولاً. يتم إنهاء التطبيقات التي تعمل في الخلفية أولاً، وعمليات النظام آخرًا. يسرد الجدول التالي فئات نتائج LMK من الأعلى إلى الأدنى. سيتم إنهاء العناصر في الفئة ذات النتيجة الأعلى، في الصف الأول، أولاً:
الشكل 4: عمليات Android، مع نتائج عالية في الأعلى ونتائج منخفضة في الأسفل
في ما يلي أوصاف للفئات المختلفة في الجدول أعلاه:
التطبيقات التي تعمل في الخلفية: هي التطبيقات التي تم تشغيلها سابقًا وليست نشطة حاليًا. ستنهي آلية LMK أولاً التطبيقات التي تعمل في الخلفية، بدءًا بالتطبيق الذي حصل على أعلى
oom_adj_score.التطبيق السابق: هو التطبيق الذي تم استخدامه مؤخرًا ويعمل في الخلفية. يحظى التطبيق السابق بأولوية أعلى (نتيجة أقل) من التطبيقات التي تعمل في الخلفية لأنّه من المرجّح أن ينتقل إليه المستخدم أكثر من أحد التطبيقات التي تعمل في الخلفية.
تطبيق Home: هو تطبيق مشغّل التطبيقات. سيؤدي إنهاء هذا التطبيق إلى اختفاء الخلفية.
الخدمات: يتم بدء الخدمات من خلال التطبيقات وقد تشمل المزامنة أو التحميل إلى السحابة الإلكترونية.
التطبيقات التي يمكن ملاحظتها: هي التطبيقات غير النشطة التي يمكن للمستخدم ملاحظتها بطريقة ما، مثل تشغيل عملية بحث تعرض واجهة مستخدم صغيرة أو الاستماع إلى الموسيقى.
تطبيق يعمل في المقدّمة: هو التطبيق قيد الاستخدام حاليًا. يبدو إنهاء التطبيق النشط وكأنّه عطل في التطبيق، ما قد يشير إلى المستخدم بأنّ هناك مشكلة في الجهاز.
الخدمات الثابتة: هي الخدمات الأساسية للجهاز، مثل خدمات الاتصال عبر الهاتف وشبكة Wi-Fi.
النظام: هي عمليات النظام. عند إنهاء هذه العمليات، قد يبدو أنّ الهاتف يعيد التشغيل.
العمليات الأصلية: هي العمليات المنخفضة المستوى جدًا التي يستخدمها النظام (على سبيل المثال،
kswapd).
يمكن لمصنّعي الأجهزة تغيير سلوك آلية LMK.
احتساب استهلاك الذاكرة
تتتبّع النواة جميع صفحات الذاكرة في النظام.
الشكل 5: الصفحات المستخدَمة من خلال عمليات مختلفة
عند تحديد مقدار الذاكرة التي يستخدمها أحد التطبيقات، يجب أن يأخذ النظام في الاعتبار الصفحات المشترَكة. ستشارك التطبيقات التي تصل إلى الخدمة أو المكتبة نفسها صفحات الذاكرة. على سبيل المثال، قد تشارك "خدمات Google Play" وتطبيق لعبة خدمة تحديد الموقع الجغرافي. يصعّب ذلك تحديد مقدار الذاكرة التي تنتمي إلى الخدمة بشكل عام مقابل كل تطبيق.
الشكل 6: الصفحات المشترَكة بين تطبيقَين (في الوسط)
لتحديد استهلاك الذاكرة لأحد التطبيقات، يمكن استخدام أي من المقاييس التالية:
- حجم مجموعة الذاكرة المقيمة (RSS): هو عدد الصفحات المشترَكة وغير المشترَكة التي يستخدمها التطبيق
- حجم مجموعة الذاكرة التناسبية (PSS): هو عدد الصفحات غير المشترَكة التي يستخدمها التطبيق وتوزيع متساوٍ للصفحات المشترَكة (على سبيل المثال، إذا كانت ثلاث عمليات تشارك 3 ميغابايت، تحصل كل عملية على 1 ميغابايت في PSS)
- حجم المجموعة الفريدة (USS): هو عدد الصفحات غير المشترَكة التي يستخدمها التطبيق (لا يتم تضمين الصفحات المشترَكة)
تكون PSS مفيدة لنظام التشغيل عندما يريد معرفة مقدار الذاكرة التي تستخدمها جميع العمليات لأنّه لا يتم احتساب الصفحات عدة مرات. يستغرق احتساب PSS وقتًا طويلاً لأنّ النظام يحتاج إلى تحديد الصفحات المشترَكة وعدد العمليات التي تشاركها. لا يميّز RSS بين الصفحات المشترَكة وغير المشترَكة (ما يجعل احتسابها أسرع)، وهي أفضل لتتبُّع التغييرات في تخصيص الذاكرة.
تشخيص رحلات المستخدم الرئيسية (CUJ) التي تستهلك قدرًا كبيرًا من الذاكرة
عند التحقيق في مشاكل الذاكرة، من المفيد تحديد رحلات المستخدم الرئيسية (CUJ) التي تستهلك قدرًا كبيرًا من الذاكرة في تطبيقك. هذه هي مهام سير عمل محددة تتطلب بطبيعتها تخصيصًا كبيرًا للذاكرة. تشمل رحلات المستخدم الرئيسية الشائعة التي تستهلك قدرًا كبيرًا من الذاكرة ما يلي:
- تحميل الوسائط المعقدة أو الصور النقطية الكبيرة ومعالجتها
- استضافة مثيلات
WebView
إذا كان تطبيقك يعتمد على محتوى الويب، يمكن أن تصبح مثيلات WebView في كثير من الأحيان عنق زجاجة خفيًا للذاكرة بسبب بنيتها المتعددة العمليات وتنفيذ الرمز الأصلي. للحصول على معلومات تشخيصية محددة وأفضل الممارسات لدورة الحياة والأدوات
المصممة خصيصًا لمحتوى الويب، يُرجى الاطّلاع على إدارة ذاكرة WebView وتشخيصها.
مراجع إضافية
- نظرة عامة على إدارة الذاكرة
- العمليات ودورة حياة التطبيق
- فهم استخدام ذاكرة Android - عرض تقديمي في Google I/O
- ذاكرة Android والألعاب - عرض تقديمي في Google I/O
- برنامج kernel swap daemon لإنهاء العمليات عند انخفاض الذاكرة في Android
مُقترَحة لك
- ملاحظة: يتم عرض نص الرابط عند إيقاف JavaScript
- وقت بدء تشغيل التطبيق