يتضمّن Android 17 والإصدارات الأحدث أداة Memory Limiter، وهي خدمة نظام تراقب استخدام الذاكرة لعمليات التطبيقات وتضبط حدودًا له باستخدام Linux cgroup v2. تمنع أداة Memory Limiter التطبيقات الفردية من استهلاك ذاكرة النظام بشكل غير متناسب، ما يقلّل من الضغط العام على الذاكرة ويمنع عمليات إيقاف العمليات المهمة التي تعمل في المقدّمة والعمليات المخزّنة مؤقتًا بسبب انخفاض الذاكرة.
الآلية
تتكامل أداة Memory Limiter مع خدمة Activity Manager Service (AMS) لتتبُّع أحداث دورة حياة العملية وتغييرات الحالة. تفرض أداة Memory Limiter حدود الذاكرة باستخدام التسلسل الهرمي Linux kernel cgroup v2.
لاستخدام أداة Memory Limiter، يجب أن يفعِّل kernel الجهاز cgroup v2 ووحدة التحكّم memory. تعتمد الخدمة تحديدًا على السمات التالية:
memory.high- حدّ مرن. عند تجاوز هذا الحد، يتم تقليل سرعة العملية ويحاول kernel استرداد الصفحات بشكل استباقي من تلك العملية.
memory.swap.max- يضبط الحدّ الأقصى لمساحة المبادلة (مثل ZRAM) التي يمكن أن تستخدمها العملية.
التأثير على التطبيقات
لا تتأثر التطبيقات التي تعمل ضمن حدود الذاكرة الخاصة بها بأداة Memory Limiter.
عندما يتجاوز تطبيق الحدّ memory.high، يزيل kernel الذاكرة النظيفة التي تم نسخها احتياطيًا من الملفات في التطبيق ويستبدل الذاكرة المجهولة غير النشطة للحفاظ على التطبيق ضمن الحدّ. نتيجةً لعملية إزالة الصفحات واستبدالها، قد يواجه التطبيق تقليلًا مؤقتًا في سرعة التنفيذ، ولكنّه يواصل التشغيل.
في الحالات القصوى، مثل تسرّب الذاكرة غير المنضبط حيث يواصل التطبيق تخصيص الذاكرة المجهولة بعد استنفاد مساحة المبادلة، يتعذّر على التطبيق تخصيص الذاكرة ويتم إنهاؤه.
مراقبة العمليات
تراقب أداة Memory Limiter عمليات التطبيقات (UID >= 10000) تلقائيًا. ويتم استثناء عمليات النظام الأساسية للحفاظ على استقرار النظام الأساسي.
تضبط أداة Memory Limiter حدود الذاكرة استنادًا إلى حالة ظهور العملية:
العمليات المرئية: العمليات التي تستضيف واجهة مستخدم مرئية للمستخدم (مثل النشاط الذي يتم التركيز عليه حاليًا أو التفاعل النشط). بما أنّ عرض واجهة المستخدم يتطلب مجموعة عمل أكبر لخطوط عرض الرسومات، تتلقّى العمليات المرئية حدًا أكثر سخاءً للذاكرة.
العمليات غير المرئية: العمليات التي تنفّذ مهامًا في الخلفية بدون عرض واجهة مستخدم (مثل الخدمات التي تعمل في الخلفية أو أجهزة استقبال البث). بما أنّ هذه العمليات لا تعرض مكوّنات واجهة المستخدم، فإنّها تعمل ضمن حدّ أكثر تقييدًا.
يربط الجدول التالي حالات العمليات المحدّدة بتصنيفات حدود الذاكرة:
| حالة العملية | حدّ الذاكرة |
|---|---|
PERSISTENT | غير محدود |
PERSISTENT_UI | غير محدود |
TOP | Visible |
BOUND_TOP | Visible |
FOREGROUND_SERVICE | غير مرئية |
BOUND_FOREGROUND_SERVICE | غير مرئية |
IMPORTANT_FOREGROUND | Visible |
IMPORTANT_BACKGROUND | غير مرئية |
TRANSIENT_BACKGROUND | غير مرئية |
BACKUP | غير مرئية |
SERVICE | غير مرئية |
RECEIVER | غير مرئية |
TOP_SLEEPING | Visible |
HEAVY_WEIGHT | غير مرئية |
HOME | غير مرئية |
LAST_ACTIVITY | غير مرئية |
CACHED_ACTIVITY | نسخة مخبأة |
CACHED_ACTIVITY_CLIENT | نسخة مخبأة |
CACHED_RECENT | نسخة مخبأة |
CACHED_EMPTY | نسخة مخبأة |
في الحالة المخزّنة مؤقتًا، يتم تجميد العمليات ثم استردادها إلى أقصى حدّ.
عندما تتجاوز عملية الحدّ memory.high المخصّص لها، ترصد أداة Memory Limiter الحدث ويمكنها تشغيل إجراءات التشخيص، مثل تسجيل ملف شخصي للذاكرة أو تسجيل حالة شاذة في statsd.
الإعداد
في Android 17 والإصدارات الأحدث، توفّر أداة Memory Limiter ملف إعداد تلقائيًا موحّدًا للنظام الأساسي على قسم النظام، مع إتاحة عمليات إلغاء اختيارية خاصة بالجهاز على قسم vendor:
- الإعداد التلقائي للنظام:
/system/etc/memory-limiter-config.xml - عملية الإلغاء الخاصة بالمورّد (اختيارية):
/vendor/etc/memory-limiter-config.xml
تبحث أداة Memory Limiter أولاً عن /vendor/etc/memory-limiter-config.xml.
إذا كان ملف الإعداد الخاص بالمورّد متوفرًا، تستخدمه الأداة، وإلا فإنّها تعود إلى الإعداد التلقائي للنظام في /system/etc/memory-limiter-config.xml.
تنسيق XML
يتّبع ملف الإعداد المخطط المحدّد في memory-limiter-config.xsd. يحدّد الملف مجموعات حدود متعددة مرتّبة حسب الذاكرة المتاحة، وتختار الخدمة أعلى مجموعة حدود مطابقة استنادًا إلى ذاكرة الوصول العشوائي المتاحة للجهاز. يتم تحديد جميع قيم الذاكرة بالميبيبايت (MiB).
<MemoryLimiterConfig>
<version>1</version>
<configList>
<!-- RAM minimums account for MemTotal excluding carve-outs. -->
<limitSet>
<!-- Limits for 16GB RAM device (MemTotal >= 13GiB): 10G/5G/5G/5G -->
<minimumRequiredMemTotal>13312</minimumRequiredMemTotal>
<memVisible>10240</memVisible>
<memNotVisible>5120</memNotVisible>
<swapVisible>5120</swapVisible>
<swapNotVisible>5120</swapNotVisible>
</limitSet>
<limitSet>
<!-- Limits for 12GB RAM device (MemTotal >= 10GiB): 8G/4G/4G/4G -->
<minimumRequiredMemTotal>10240</minimumRequiredMemTotal>
<memVisible>8192</memVisible>
<memNotVisible>4096</memNotVisible>
<swapVisible>4096</swapVisible>
<swapNotVisible>4096</swapNotVisible>
</limitSet>
<limitSet>
<!-- Limits for 8GB RAM device (MemTotal >= 6.5GiB): 5G/3G/3G/3G -->
<minimumRequiredMemTotal>6656</minimumRequiredMemTotal>
<memVisible>5120</memVisible>
<memNotVisible>3072</memNotVisible>
<swapVisible>3072</swapVisible>
<swapNotVisible>3072</swapNotVisible>
</limitSet>
<limitSet>
<!-- Limits for 6GB RAM device (MemTotal >= 4.5GiB): 4G/2G/2G/2G -->
<minimumRequiredMemTotal>4608</minimumRequiredMemTotal>
<memVisible>4096</memVisible>
<memNotVisible>2048</memNotVisible>
<swapVisible>2048</swapVisible>
<swapNotVisible>2048</swapNotVisible>
</limitSet>
<limitSet>
<!-- Limits for 4GB RAM device (MemTotal >= 3GiB): 2G/1G/1G/1G -->
<minimumRequiredMemTotal>3072</minimumRequiredMemTotal>
<memVisible>2048</memVisible>
<memNotVisible>1024</memNotVisible>
<swapVisible>1024</swapVisible>
<swapNotVisible>1024</swapNotVisible>
</limitSet>
</configList>
</MemoryLimiterConfig>
version- عدد صحيح موجب يحدّد إصدار الإعداد. يجب أن تكون القيمة
1. minimumRequiredMemTotalالحدّ الأدنى لـ
MemTotalفي النظام (بالميبيبايت) المطلوب لتطبيق مجموعة الحدود هذه. تقارن الخدمة هذه القيمة بإجمالي الذاكرة المتاحة التي يبلغ عنها kernel في/proc/meminfo.فهم عمليات تخصيص الذاكرة: تعكس قيمة
MemTotalفي kernel ذاكرة الوصول العشوائي الديناميكية (DRAM) الفعلية التي يمكن لنظام التشغيل الوصول إليها بعد خصم عمليات تخصيص الذاكرة للأجهزة والبرامج الثابتة. تحجز عمليات التخصيص ذاكرة الوصول العشوائي لمكوّنات الأجهزة المتخصّصة، مثل وحدة معالجة الرسومات (GPU) ومودم النطاق الأساسي ومزوّد خدمة الإنترنت للكاميرا (ISP) وبيئات التنفيذ الآمنة والمشرفين، وعادةً ما تستهلك ما بين 500 ميبيبايت وأكثر من 1 غيبيبايت من الذاكرة الفعلية.بما أنّ
MemTotalأقل من ذاكرة الوصول العشوائي الديناميكية (DRAM) الفعلية التي تم الإعلان عنها للجهاز، تتضمّن الحدودminimumRequiredMemTotalهامشًا لعمليات التخصيص هذه. على سبيل المثال، يحدّد إعداد يستهدف الأجهزة التي تبلغ سعتها 16 غيغابايتminimumRequiredMemTotalبقيمة13312(13 غيغابايت) بدلاً من16384(16 غيغابايت)، ويحدّد مستوى للأجهزة التي تبلغ سعتها 12 غيغابايت10240(10 غيغابايت). يضمن ذلك أن يتطابق كل جهاز مع المستوى المقصود بغض النظر عن الاختلافات في عمليات التخصيص على مستوى اللوحة.memVisibleحدّ الذاكرة المرن (
memory.high) بالميبيبايت الذي يتم تطبيقه على العمليات المرئية.memNotVisibleحدّ الذاكرة المرن (
memory.high) بالميبيبايت الذي يتم تطبيقه على العمليات غير المرئية.swapVisibleحدّ مساحة المبادلة (
memory.swap.max) بالميبيبايت الذي يتم تطبيقه على العمليات المرئية.swapNotVisibleحدّ مساحة المبادلة (
memory.swap.max) بالميبيبايت الذي يتم تطبيقه على العمليات غير المرئية.
الحدود العادية للنظام الأساسي
في Android 17 والإصدارات الأحدث، يحدّد النظام الأساسي حدودًا عادية للذاكرة والمبادلة في /system/etc/memory-limiter-config.xml على مستوى مستويات ذاكرة الوصول العشوائي الديناميكية (DRAM) الفعلية الشائعة:
| ذاكرة الوصول العشوائي الديناميكية (DRAM) الفعلية المستهدَفة |
الحدّ الأدنى المطلوب MemTotal (minimumRequiredMemTotal) |
حدّ الذاكرة المرئية (memVisible) |
حدّ الذاكرة غير المرئية (memNotVisible) |
حدّ المبادلة المرئية (swapVisible) |
حدّ المبادلة غير المرئية (swapNotVisible) |
|---|---|---|---|---|---|
| 16 غيغابايت | 13,312 ميبيبايت (13 غيغابايت) | 10,240 ميبيبايت (10 غيغابايت) | 5,120 ميبيبايت (5 غيغابايت) | 5,120 ميبيبايت (5 غيغابايت) | 5,120 ميبيبايت (5 غيغابايت) |
| 12 غيغابايت | 10,240 ميبيبايت (10 غيغابايت) | 8,192 ميبيبايت (8 غيغابايت) | 4,096 ميبيبايت (4 غيغابايت) | 4,096 ميبيبايت (4 غيغابايت) | 4,096 ميبيبايت (4 غيغابايت) |
| 8 غيغابايت | 6,656 ميبيبايت (6.5 غيغابايت) | 5,120 ميبيبايت (5 غيغابايت) | 3,072 ميبيبايت (3 غيغابايت) | 3,072 ميبيبايت (3 غيغابايت) | 3,072 ميبيبايت (3 غيغابايت) |
| 6 غيغابايت | 4,608 ميبيبايت (4.5 غيغابايت) | 4,096 ميبيبايت (4 غيغابايت) | 2,048 ميبيبايت (2 غيغابايت) | 2,048 ميبيبايت (2 غيغابايت) | 2,048 ميبيبايت (2 غيغابايت) |
| 4 غيغابايت | 3,072 ميبيبايت (3 غيغابايت) | 2,048 ميبيبايت (2 غيغابايت) | 1,024 ميبيبايت (1 غيغابايت) | 1,024 ميبيبايت (1 غيغابايت) | 1,024 ميبيبايت (1 غيغابايت) |
مبادئ حدود الذاكرة
تم تصميم إعداد أداة Memory Limiter استنادًا إلى مبادئ النظام الأساسي التالية:
الاتساق في المنظومة المتكاملة وتوافق التطبيقات: تضمن حدود الذاكرة المتسقة على مستوى الأجهزة أداء التطبيق المتوقع في جميع أنحاء منظومة Android المتكاملة. يتم تطوير التطبيقات واختبارها استنادًا إلى التوقعات العادية للذاكرة، ويؤدي الحفاظ على حدود موحّدة للنظام الأساسي إلى تجنُّب تقليل السرعة غير المتوقّع أو عمليات الإنهاء المبكرة.
تخصيص الموارد بشكل متناسب: تتم معايرة حدود النظام الأساسي وفقًا لسعة ذاكرة الوصول العشوائي الديناميكية (DRAM) الفعلية:
- العمليات المرئية: يتم تخصيص ما يقرب من 1/2 إلى 2/3 من إجمالي ذاكرة الوصول العشوائي الديناميكية (DRAM) الفعلية لدعم أحمال العمل النشطة لواجهة المستخدم والتركيب والعرض.
- العمليات غير المرئية: يتم تخصيص ما يقرب من 1/4 إلى 1/3 من إجمالي ذاكرة الوصول العشوائي الديناميكية (DRAM) الفعلية للمهام التي تعمل في الخلفية.
إمكانية التطبيق الشاملة: تنطبق الحدود بشكل موحّد على جميع عمليات التطبيقات على الجهاز (UID >= 10000)، بما في ذلك تطبيقات النظام والتطبيقات الأصلية المثبّتة مسبقًا. لا تتيح أداة Memory Limiter قوائم السماح لاستثناء تطبيقات محدّدة، ما يضمن إدارة عادلة للذاكرة على مستوى جميع التطبيقات.
عدم توفّر واجهات برمجة تطبيقات للاستعلام في وقت التشغيل: في Android 17 والإصدارات الأحدث، لا يمكن للتطبيقات الاستعلام عن حدود الذاكرة المخصّصة لها بشكل آلي في وقت التشغيل. يتم تحديد الحدود العادية للنظام الأساسي مع هوامش كبيرة حتى تعمل التطبيقات التي تتصرف بشكل جيد بدون قيود أثناء الاستخدام العادي.
ديناميكيات استرداد kernel والمبادلة: عندما تقترب عملية التطبيق من الحدّ
memory.high، يوجّه kernel في Linux عملية استرداد الذاكرة تحديدًا إلى مجموعة cgroup الخاصة بتلك العملية. ويشمل ذلك إزالة الصفحات غير النشطة التي تم نسخها احتياطيًا من الملفات واستبدال الصفحات المجهولة غير النشطة بـ ZRAM، ما يحافظ على سلاسة النظام بدون فرض ضغط عالمي على الذاكرة.
أوامر Shell
يتيح الأمر am memory-limiter للمطوّرين ومدمجي الأنظمة التفاعل مع الخدمة في وقت التشغيل لأغراض التطوير والاختبار وتحديد الأخطاء وإصلاحها:
am memory-limiter <SUB-COMMAND>status
يعرض الأمر الفرعي status حالة التشغيل والمقاييس النشطة لأداة Memory Limiter:
adb shell am memory-limiter statusمثال على الإخراج:
Memory limiter
enabled monitoring=true ignored=none
visibleMem=1948MB visibleSwap=974MB
notVisibleMem=974MB notVisibleSwap=487MB
started=36 watched=36 watch-failed=0
events=0 processes=36 process-hwm=36
تشمل الحقول الرئيسية في الإخراج ما يلي:
monitoring- يشير إلى ما إذا كانت أداة Memory Limiter تراقب العمليات بشكل نشط.
visibleMemوnotVisibleMem- حدود الذاكرة المطلقة المحسوبة (
memory.high) التي يتم فرضها حاليًا لكل حالة ظهور. visibleSwapوnotVisibleSwap- حدود المبادلة المطلقة المحسوبة (
memory.swap.max) التي يتم فرضها حاليًا لكل حالة ظهور. events- عدد المرّات التي تجاوزت فيها العملية الحدّ المخصّص لها.
processes- العدد الحالي للعمليات التي تتم مراقبتها.
ignore
يستبعد الأمر الفرعي ignore مؤقتًا معرّف مستخدم (UID) محدّدًا أو جميع العمليات من ضبط حدود الذاكرة. ويكون ذلك مفيدًا لقياس الأداء أو إجراء اختبارات التحمّل أو تشخيص سلوك الذاكرة:
# Ignore a specific UID adb shell am memory-limiter ignore 10087# Ignore all processes (temporarily disables limiting) adb shell am memory-limiter ignore all# Resume normal limiting operation adb shell am memory-limiter ignore none
manual
يلغي الأمر الفرعي manual الحدود المحسوبة لعملية محدّدة حسب رقم تعريف العملية (PID) باستخدام قيمة مطلقة مخصّصة بالبايت. يجب أن تكون القيمة عددًا صحيحًا، ولكن يمكن أن تتضمّن اللاحقة MB للإشارة إلى الميبيبايت أو اللاحقة GB للإشارة إلى الغيبيبايت:
# Set a 1GiB limit for PID 1234 adb shell am memory-limiter manual 1234 1073741824# Set a 1GiB limit for PID 1234 adb shell am memory-limiter manual 1234 1024MB# Set a 1GiB limit for PID 1234 adb shell am memory-limiter manual 1234 1GB# Remove the manual override for PID 1234 adb shell am memory-limiter manual 1234 none
لا تسري عمليات الإلغاء اليدوية إلا طوال فترة بقاء مثيل العملية المحدّد. إذا أعيد تشغيل العملية، فإنّها تعود إلى الحدود العادية استنادًا إلى حالتها.
لا يمكن أن تتجاوز عملية الإلغاء اليدوية حدود النظام الفعلية.