أداة تحديد الذاكرة

يتضمّن 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غير محدود
TOPVisible
BOUND_TOPVisible
FOREGROUND_SERVICEغير مرئية
BOUND_FOREGROUND_SERVICEغير مرئية
IMPORTANT_FOREGROUNDVisible
IMPORTANT_BACKGROUNDغير مرئية
TRANSIENT_BACKGROUNDغير مرئية
BACKUPغير مرئية
SERVICEغير مرئية
RECEIVERغير مرئية
TOP_SLEEPINGVisible
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

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

لا يمكن أن تتجاوز عملية الإلغاء اليدوية حدود النظام الفعلية.