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

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

آلية العمل

يتكامل Memory Limiter مع خدمة "مدير الأنشطة" (AMS) لتتبُّع أحداث دورة حياة العمليات وتغييرات الحالة. يفرض Memory Limiter حدود الذاكرة باستخدام التسلسل الهرمي cgroup v2 لنواة Linux.

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

memory.high
حدّ أقصى مرن وعند تجاوز هذا الحد، يتم تقييد العملية ويحاول النواة استرداد الصفحة بشكل استباقي من تلك العملية.
memory.swap.max
يحدّد الحد الأقصى لمقدار مساحة التبديل (مثل ZRAM) التي يمكن للعملية استخدامها.

التأثير على التطبيقات

لا يتأثر التطبيقات التي تعمل ضمن حدود الذاكرة المسموح بها بأداة Memory Limiter.

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

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

مراقبة العمليات

يراقب "أداة تحديد سقف استخدام الذاكرة" عمليات التطبيقات (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.

الإعداد

في الإصدار 17 من نظام التشغيل Android والإصدارات الأحدث، يتم ضبط أداة Memory Limiter باستخدام ملف إعداد النظام الأساسي العادي في قسم النظام على /system/etc/memory-limiter-config.xml.

تنسيق XML

يتّبع ملف الإعداد المخطط المحدّد في memory-limiter-config.xsd. يحدّد الملف عدة مجموعات من الحدود مرتبة حسب الذاكرة المتاحة، وتختار الخدمة أعلى مجموعة حدود مطابقة استنادًا إلى ذاكرة الوصول العشوائي المتاحة على الجهاز. يتم تحديد جميع قيم الذاكرة بالميبيبايت (MiB).

<MemoryLimiterConfig>
  <version>1</version>
  <configList>
    <!-- RAM boundaries account for MemTotal excluding carve-outs. -->
    <limitSet>
      <!-- Limits for 16GB RAM device [14336, 18432): 10G/5G/5G/5G -->
      <minimumRequiredMemTotal>14336</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>18432</maximumAllowedMemTotal>
      <memVisible>10240</memVisible>
      <memNotVisible>5120</memNotVisible>
      <swapVisible>5120</swapVisible>
      <swapNotVisible>5120</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 12GB RAM device [9216, 14336): 8G/4G/4G/4G -->
      <minimumRequiredMemTotal>9216</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>14336</maximumAllowedMemTotal>
      <memVisible>8192</memVisible>
      <memNotVisible>4096</memNotVisible>
      <swapVisible>4096</swapVisible>
      <swapNotVisible>4096</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 8GB RAM device [6800, 9216): 5G/3G/3G/3G -->
      <minimumRequiredMemTotal>6800</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>9216</maximumAllowedMemTotal>
      <memVisible>5120</memVisible>
      <memNotVisible>3072</memNotVisible>
      <swapVisible>3072</swapVisible>
      <swapNotVisible>3072</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 6GB RAM device [4800, 6800): 4G/2G/2G/2G -->
      <minimumRequiredMemTotal>4800</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>6800</maximumAllowedMemTotal>
      <memVisible>4096</memVisible>
      <memNotVisible>2048</memNotVisible>
      <swapVisible>2048</swapVisible>
      <swapNotVisible>2048</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 4GB RAM device [3200, 4800): 2G/1G/1G/1G -->
      <minimumRequiredMemTotal>3200</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>4800</maximumAllowedMemTotal>
      <memVisible>2048</memVisible>
      <memNotVisible>1024</memNotVisible>
      <swapVisible>1024</swapVisible>
      <swapNotVisible>1024</swapNotVisible>
    </limitSet>
  </configList>
</MemoryLimiterConfig>
version
عدد صحيح موجب يحدّد إصدار الإعداد. يجب أن يكون هذا 1.
minimumRequiredMemTotal

الحد الأدنى من مساحة النظام MemTotal (بالميغابايت، بما في ذلك الحد الأدنى) المطلوب لتطبيق مجموعة الحدود هذه. وتقارن الخدمة هذا الرقم بإجمالي الذاكرة المتاحة التي أبلغت عنها النواة في /proc/meminfo.

فهم حدود الذاكرة المخصّصة: تعكس قيمة MemTotal نواة النظام مقدار ذاكرة الوصول العشوائي الديناميكية (DRAM) الفعلية التي يمكن لنظام التشغيل الوصول إليها بعد خصم الذاكرة المخصّصة للأجهزة والبرامج الثابتة. تخصّص عمليات التقسيم ذاكرة الوصول العشوائي (RAM) لمكوّنات الأجهزة المتخصّصة، مثل وحدة معالجة الرسومات (GPU) ومودم النطاق الأساسي ومعالج إشارات الصور (ISP) الخاص بالكاميرا وبيئات التنفيذ الآمنة وبرامج Hypervisor، وعادةً ما تستهلك ما بين 500 ميغابايت وأكثر من 2 غيغابايت من الذاكرة الفعلية.

بما أنّ قيمة MemTotal أقل من ذاكرة الوصول العشوائي الديناميكية (DRAM) الفعلية المُعلن عنها للجهاز، تتضمّن حدود minimumRequiredMemTotal الدنيا هامشًا لهذه المساحات المخصّصة. على سبيل المثال، يحدّد الإعداد الذي يستهدف الأجهزة بسعة 16 غيغابايت حدًا أدنى يبلغ 14336 (14 غيغابايت) بدلاً من 16384 (16 غيغابايت)، ويحدّد مستوى الأجهزة بسعة 12 غيغابايت حدًا أدنى يبلغ 9216 (9 غيغابايت). ويضمن ذلك أن يتوافق كل جهاز مع الفئة المقصودة بغض النظر عن الاختلافات في التصميم على مستوى اللوحة.

maximumAllowedMemTotal

تمثّل هذه السمة الحد الأقصى لنظام MemTotal (بوحدة MiB، الحد الأعلى غير شامل) الذي يجب أن ينطبق على مجموعة الحدود هذه. إذا كان MemTotal أكبر من أو يساوي هذا الحد الأقصى، لن يسري الحدّ الذي تم ضبطه. بالنسبة إلى الأجهزة التي تبلغ سعتها 18,432 مبيبايت أو أكثر أو الأجهزة التي تقل سعتها عن 3,200 مبيبايت، لا يفرض Memory Limiter أي قيود، ما يترك العمليات بدون قيود.

memVisible

الحد الأقصى المبدئي للذاكرة (memory.high) بوحدة MiB الذي يتم تطبيقه على العمليات المرئية

memNotVisible

الحدّ الأقصى المبدئي للذاكرة (memory.high) بوحدة قياس "ميغابايت" الذي يتم تطبيقه على العمليات غير المرئية

swapVisible

الحد الأقصى لمساحة التبديل (memory.swap.max) بوحدة MiB المطبّق على العمليات المرئية

swapNotVisible

الحد الأقصى لمساحة التبديل (memory.swap.max) بوحدة MiB المطبّق على العمليات غير المرئية

الحدود القصوى العادية للمنصة

في الإصدار 17 من نظام التشغيل Android والإصدارات الأحدث، تحدّد المنصة حدودًا عادية للذاكرة ومساحة التبديل في /system/etc/memory-limiter-config.xml عبر فئات ذاكرة الوصول العشوائي (RAM) الشائعة باستخدام فواصل النطاق [floor, ceiling):

استهداف ذاكرة الوصول العشوائي المادية نطاق MemTotal [floor, ceiling)
(minimumRequiredMemTotal,
maximumAllowedMemTotal)
حد الذاكرة المرئية
(memVisible)
الحدّ الأقصى للذاكرة غير المرئية
(memNotVisible)
حدّ التبديل المرئي
(swapVisible)
الحد الأقصى لعدد عمليات الاستبدال غير المرئية
(swapNotVisible)
‫16 غيغابايت [14336, 18432) ميبيبايت ‫10,240 ميبي بايت (10 غيبي بايت) ‫5,120 ميبيبايت (5 غيبيبايت) ‫5,120 ميبيبايت (5 غيبيبايت) ‫5,120 ميبيبايت (5 غيبيبايت)
‫12 غيغابايت [9216, 14336) ميبيبايت ‫8,192 ميبي بايت (8 غيبي بايت) ‫4,096 ميغابايت (4 غيغابايت) ‫4,096 ميغابايت (4 غيغابايت) ‫4,096 ميغابايت (4 غيغابايت)
‫8 غيغابايت [6800, 9216) ميبيبايت ‫5,120 ميبيبايت (5 غيبيبايت) ‫3,072 ميغابايت (3 غيغابايت) ‫3,072 ميغابايت (3 غيغابايت) ‫3,072 ميغابايت (3 غيغابايت)
‫6 غيغابايت [4800, 6800) ميبيبايت ‫4,096 ميغابايت (4 غيغابايت) ‫2,048 ميبي بايت (2 غيبي بايت) ‫2,048 ميبي بايت (2 غيبي بايت) ‫2,048 ميبي بايت (2 غيبي بايت)
‫4 غيغابايت [3200, 4800) ميبيبايت ‫2,048 ميبي بايت (2 غيبي بايت) ‫1,024 ميبيبايت (1 غيبيبايت) ‫1,024 ميبيبايت (1 غيبيبايت) ‫1,024 ميبيبايت (1 غيبيبايت)

مبادئ حدود الذاكرة

تم تصميم إعدادات "أداة تحديد سقف استخدام الذاكرة" وفقًا لمبادئ النظام الأساسي التالية:

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

  • تخصيص الموارد بشكل نسبي: يتم ضبط حدود المنصة وفقًا لسعة ذاكرة الوصول العشوائي (RAM) المادية:

    • العمليات المرئية: تم تخصيص ما يقرب من نصف إجمالي ذاكرة الوصول العشوائي (RAM) الفعلية إلى ثلثَيها لدعم أحمال العمل النشطة الخاصة بواجهة المستخدم والتركيب والعرض.
    • العمليات غير المرئية: يتم تخصيص ما يقرب من ربع إلى ثلث إجمالي ذاكرة الوصول العشوائي (RAM) الفعلية للمهام التي تعمل في الخلفية.
  • إمكانية التطبيق على نطاق واسع: تنطبق الحدود بشكل موحّد على جميع عمليات التطبيقات على الجهاز (معرّف المستخدم >= 10000)، بما في ذلك تطبيقات النظام والتطبيقات المثبّتة مسبقًا من الشركة المصنّعة للجهاز. لا يتيح تطبيق &quot;محدد الذاكرة&quot; قوائم السماح لاستثناء تطبيقات معيّنة، ما يضمن إدارة الذاكرة بشكل عادل في جميع التطبيقات.

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

  • ديناميكيات استرداد الذاكرة وتبديلها في النواة: عندما تقترب عملية أحد التطبيقات من الحدّ الأقصى memory.high، توجّه نواة 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
يشير إلى ما إذا كان "محدد الذاكرة" يراقب العمليات بشكل نشط.
visibleMem وnotVisibleMem
الحدود القصوى المطلقة للذاكرة (memory.high) التي يتم تطبيقها حاليًا على كل حالة ظهور
visibleSwap وnotVisibleSwap
تم حاليًا فرض حدود التبديل المطلقة المحسوبة (memory.swap.max) لكل حالة ظهور.
events
عدد المرّات التي تجاوزت فيها عملية الحدّ المخصّص لها
processes
عدد العمليات التي تتم مراقبتها حاليًا:

تجاهل

يستبعد الأمر الفرعي 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 محلّ الحدود المحسوبة لعملية معيّنة حسب معرّف العملية (PID) بقيمة مطلقة مخصّصة بالبايت. يجب أن تكون القيمة عددًا صحيحًا، ولكن يمكن أن تتضمّن اللاحقة MB للإشارة إلى MiB أو اللاحقة GB للإشارة إلى GiB:

# 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

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

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