في الإصدار 17 من نظام التشغيل Android والإصدارات الأحدث، تتحكّم المنصة في ذاكرة عمليات النظام باستخدام آليتَين تكميليتَين من الإصدار الثاني من مجموعة التحكّم (cgroup) في نظام التشغيل Linux، وتعملان جنبًا إلى جنب مع محدِّد الذاكرة العام للتطبيقات:
- الحدود الدنيا لحماية برامج daemon للنظام (
SystemMemoryBudgetManagerمعmemory.min): تحمي حجوزاتmemory.minذاتية الضبط في الإصدار الثاني من cgroup (تم ضبطها على %90 من مجموعة العمل المقيمة المستقرة لكل برنامج daemon وتم تحديد سقفها على مستوى العالم بنسبة% 10 من إجمالي ذاكرة الوصول العشوائي الفعلية) برامج daemon التفاعلية المهمة وعمليات واجهة الأوامر (system_serverوsurfaceflingerوcomposerHAL للرسومات وaudioserverوcameraserverوnetdوSystemUIومشغّل الشاشة الرئيسية) تحت ضغط الذاكرة، لتحل محل تثبيت ملفاتPinnerServicemlockالثابتة. - الحدود القصوى لذاكرة تطبيقات النظام (
<memory-budget>معmemory.high): يتم تحديد الحدود المرنةmemory.highلمجموعة التحكم cgroup v2 التي تمت معايرتها حسب حجم العمل (عادةً من 30 ميغابايت إلى 190 ميغابايت) في ملفات البيان لتطبيقات النظام الثابتة والتي تعمل في الخلفية (BluetoothوNfcوCalendarProviderوTraceurوMediaProviderو:PhotoPickerوNetworkStackوAppSearchوTeleService) لاستعادة ذاكرة التخزين المؤقت لصفحات الملفات غير النشطة والكومة المجهولة المصدر بعد الاندفاع بشكل استباقي قبل حدوث ضغط على الذاكرة العامة.
يقارن الجدول التالي بين الآليتَين:
| البُعد | الحدود الدنيا لحماية برامج النظام الخفية | الحدود القصوى لذاكرة تطبيقات النظام |
|---|---|---|
| خدمة المنصة | SystemMemoryBudgetManager |
MemoryLimiter |
| التحكّم في Cgroup v2 | الحد الأدنى الصارم للحماية: memory.min |
الحد الأقصى المرن لاسترداد الموارد: memory.high |
| العمليات المستهدَفة | البرامج الخفية التفاعلية وواجهة مستخدم واجهة الأوامر التي تتأثر بوقت الاستجابة (system_server وsurfaceflinger وcomposer HAL وaudioserver وcameraserver وnetd وSystemUI وتطبيق Home) |
تطبيقات النظام الثابتة والتي لا تتضمّن واجهة مستخدم، وأدوات توفير المحتوى، والخدمات التي تُشغَّل في الخلفية (مثل Bluetooth وNfc وMediaProvider وNetworkStack وAppSearch وTeleService) |
| نموذج تحديد الحجم | ضبط ذاتي في وقت التشغيل (90% من مجموعة العمل المستقرة، بحد أقصى 10% من إجمالي ذاكرة الوصول العشوائي على مستوى العالم) بدون جداول ضبط لكل جهاز | سمات XML لبيان <memory-budget> التعريفي التي تمت معايرتها حسب فئة ذاكرة الوصول العشوائي (RAM) وحالة العملية وعدد وحدات بكسل الشاشة |
| الميزة الأساسية | تمنع هذه الميزة حدوث أي خلل في واجهة المستخدم التفاعلية وتوقُّف التنشيط في حال الضغط على الذاكرة أثناء استبدال قوائم ملفات PinnerService mlock الثابتة |
تزيل هذه الميزة باستمرار ذاكرة التخزين المؤقت للملفات غير النشطة التي يتم استخدامها لمرة واحدة والذاكرة الديناميكية بعد زيادة الاستخدام، وذلك لتوفير المزيد من ذاكرة RAM الفعلية للتطبيقات التي تعمل في المقدّمة والتطبيقات المخزَّنة مؤقتًا |
لمزيد من المعلومات حول بنية <memory-budget> وسمات XML وواجهات برمجة التطبيقات لوقت التشغيل
واحتساب ذاكرة نظام التشغيل، يُرجى الاطّلاع على ضبط حدود استخدام الذاكرة في التطبيقات
وفهم ذاكرة Android وتحديد مشاكلها وحلّها.
حماية برامج الخلفية التفاعلية المهمة باستخدام SystemMemoryBudgetManager
يحتفظ SystemMemoryBudgetManager بالعمليات التي تقع مباشرةً في مسار المستخدم التفاعلي في ذاكرة الوصول العشوائي (RAM) الفعلية أثناء ضغط الذاكرة. بدلاً من
تثبيت قائمة ثابتة من ملفات APK وODEX وVDEX في الذاكرة باستخدام
mlock (كما يفعل PinnerService لـ config_defaultPinnerServiceFiles و
config_pinnerHomePinBytes)، يخصّص SystemMemoryBudgetManager الحد الأدنى لـ memory.min في الإصدار الثاني من مجموعة التحكم (cgroup) الديناميكية
للعمليات التالية:
- شريحة النظام الأساسية (
/sys/fs/cgroup/system):system_serverوsurfaceflingerو"طبقة تجريد الأجهزة" (HAL) لرسوماتcomposerوaudioserverوcameraserverوnetd، بالإضافة إلى أي نظام أصلي خاص بعامل الشكل أو برامج الخلفية الخاصة بالمورّدين والمُدرَجة فيconfig_systemMemoryBudgetAdditionalSystemProcesses(على سبيل المثال،android.hardware.perceptionhostوauracamerahalعلى أجهزة XR). - شريحة التطبيق التفاعلية (
/sys/fs/cgroup/apps): العملية الرئيسية لحزمة SystemUI التي تم ضبطها (config_systemUi) والعملية الرئيسية لدور الشاشة الرئيسية للمستخدم الحالي.
إنّ حماية حامل دور "الصفحة الرئيسية" إلى جانب "config_systemUi" يضمن التغطية على جميع أشكال الأجهزة. على أشكال الأجهزة التي يكون فيها config_systemUi حزمة توافق خفيفة (مثل Wear OS، حيث يتم تشغيل خلفية شاشة الساعة والإشعارات والمربّعات داخل تطبيق Home)، لا يزال الغلاف الموجّه للمستخدمين يحصل على حماية كاملة لمجموعة العمل. إذا تم حلّ نية Home إلى حزمة config_systemUi، تتم حماية العملية مرة واحدة. تتلقّى العملية الرئيسية فقط لكل حزمة (processName == packageName) حدًا أدنى للحماية، وبالتالي لا تستهلك العمليات الفرعية المساعدة (مثل :screenshot) ميزانية الحماية.
سياسة الضبط الذاتي وتفويض cgroup على ثلاثة مستويات
بما أنّ مجموعة العمل لبرنامج daemon التفاعلي تختلف بشكل كبير حسب أشكال الأجهزة وسعات ذاكرة الوصول العشوائي (على سبيل المثال، يستخدم SystemUI حوالي 45 ميغابايت على ساعة ذكية، و60 ميغابايت على هاتف بسعة 6 غيغابايت، و180 ميغابايت على هاتف بسعة 16 غيغابايت)، فإنّ جداول البحث الثابتة لكل جهاز تكون غير مستقرة. بدلاً من ذلك،
يستمدّ SystemMemoryBudgetManager الحدود الدنيا مباشرةً من البصمة المقيمة لكل عملية
باستخدام ثلاثة ثوابت:
| مَعلمة السياسة | القيمة التلقائية | السلوك |
|---|---|---|
| الحد الأدنى لكل عملية | 90% من ملفات memory.current التي تمت تسويتها باستثناء ذاكرة التخزين المؤقت للملفات غير المرتبطة |
تحمي هذه الميزة الرموز البرمجية المجهولة المصدر في الذاكرة الديناميكية والذاكرة المؤقتة والذاكرة المخصّصة، مع ترك آخر% 10 من الرموز البرمجية الأقل استخدامًا قابلة للاسترداد، ما يتيح إزالة الصفحات غير المستخدَمة فعليًا. يتم طرح ذاكرة التخزين المؤقت للملفات غير المرتبطة (max(0, file - shmem - file_mapped) من memory.stat) قبل تطبيق نسبة% 90، وبالتالي لا تؤدي ذاكرة التخزين المؤقت لفحص الحزمة عند التشغيل أو قراءة مواد العرض لمرة واحدة إلى زيادة الحد الأدنى. |
| الحدّ الأقصى العام لذاكرة الوصول العشوائي (RAM) | % 10 من إجمالي ذاكرة الوصول العشوائي (config_systemMemoryBudgetLowKb) |
تتطابق مع حاجز الوقاية config_pinnerMaxPinnedMemoryPercentage في PinnerService. إذا تجاوز مجموع الحد الأدنى للسعر بنسبة% 90 نسبة% 10 من MemTotal، يتم خفض كل حد أدنى للسعر بشكل نسبي بالعامل نفسه. |
| وتيرة إعادة التحميل | بعد ثانية واحدة و4 ثوانٍ و16 ثانية و64 ثانية من البدء، ثم كل 30 دقيقة | تتقارب سلسلة هندسية من عمليات الاستقرار على مجموعة العمل لكل برنامج خفي بعد بدء التشغيل بدون ترميز تأخيرات الإحماء لكل جهاز، وتتتبّع عملية إعادة التحميل في الحالة الثابتة لمدة 30 دقيقة النمو التدريجي لمجموعة العمل وانكماشها على مدار عمر الجهاز. |
في وحدة التحكّم في الذاكرة cgroup v2 في Linux
(mm/memcontrol.c:effective_protection)، يكون الحد الأقصى للحماية الفعّالة memory.min لمجموعة cgroup فرعية
محدودًا بالقيمة memory.min التي تم ضبطها على مجموعات cgroup الرئيسية
والسابقة. يؤدي ضبط السياسة memory.min على دليل pid_<pid> فرعي فقط
بينما تكون السياسة uid_<uid>/memory.min مضبوطة على 0 إلى عدم توفير أي حماية فعّالة.
في المقابل، يؤدي ضبط قيمة ثابتة لـ memory.min على الشريحة
/sys/fs/cgroup/system العليا فقط إلى توزيع الحماية غير المستخدَمة على جميع معرّفات UID
الفرعية والعمليات بشكل متناسب (memory_recursiveprot)، ما يسمح للعمليات التشخيصية
أو الثانوية التي تشارك uid_1000 (android.uid.system) بسحب
الحماية من surfaceflinger وaudioserver.
لتوفير عزل دقيق لكل برنامج خفي، يكتب SystemMemoryBudgetManager
الحماية على جميع المستويات الثلاثة للتسلسل الهرمي لـ cgroup v2 في كل عملية إعادة تحميل،
كما هو موضّح في الشكل 1:
- عقدة عملية طرفية (
pid_<pid>/memory.min): يتم ضبطها على الحد الأدنى لمجموعة العمل (المُعدَّلة) بنسبة% 90 للعملية. - عقدة UID (
uid_<uid>/memory.min): يتم ضبطها على المجموع الدقيق للحدود الدنياpid_*المُدارة، وبالتالي فإنّ العمليات غير المُدارة التي تشارك معرّف UID هذا (مثل برامجAID_SYSTEMالخفية الأخرى أو حزمsharedUserId="android.uid.system")memory.min = 0ولا يمكنها المطالبة بالحماية. - الشريحة ذات المستوى الأعلى (
/sys/fs/cgroup/system/memory.minو/sys/fs/cgroup/apps/memory.min): يتم ضبطها على المجموع الدقيق للشرائح الفرعيةuid_*. تتم إزالة أي قيمmemory.lowقديمة في العُقد المُدارة إلى0، وتتم إعادة ضبط أي أدلةuid_*تمت إدارتها في عملية إعادة تحميل سابقة (مثل مشغّل الصفحة الرئيسية السابق بعد تبديل المستخدم للمشغّلات) إلى0.
الشكل 1: تفويض الحد الأدنى للحماية على ثلاثة مستويات عبر شرائح cgroup
سبب استخدام memory.min بدلاً من memory.low في نواة MGLRU
في إطار Multi-Generational LRU (MGLRU، وهو محرّك استعادة الصفحات التلقائي في Android 6.6 والنواة الأحدث)، يتصرف memory.low وmemory.min بشكل مختلف في mm/vmscan.c:shrink_one:
-
memory.low(تأجيل لمرة واحدة): يتم نقل مجموعة التحكم التي يقل استخدامها عنmemory.lowإلى نهاية قائمة "الأقل استخدامًا مؤخرًا" (LRU) في memcg (MEMCG_LRU_TAIL) ويتم تخطّيها لمرة واحدة في عملية استرداد الذاكرة. في المرة التالية التي يواجه فيها النظام ضغطًا مستمرًا على الذاكرة، تستعيد النواة مجموعة التحكم بالكامل وتسجّل حدثMEMCG_LOW. في اختبارات الضغط على الأجهزة الفعلية مع زيادة استهلاك الذاكرة المجهولة المصدر إلى% 85 من ذاكرة الوصول العشوائي الفعلية، سمحmemory.lowلـSystemUIعلى ساعة ذكية بالانخفاض من حوالي 45 ميغابايت إلى حوالي 5 إلى 10 ميغابايت وaudioserverعلى جهاز قابل للطي بسعة 16 غيغابايت بالانخفاض من 15 ميغابايت إلى 2 ميغابايت مقابل حد أدنى يبلغ حوالي 14 ميغابايت. memory.min(الحد الأدنى الصارم للحماية): يتم تخطّي مجموعة التحكّم التي يقل استخدامها عنmemory.minمن خلال عملية الاسترداد الشاملة. كما هو موضّح في الشكل 2، في ظل عبء العمل نفسه الذي يبلغ% 85 من ضغط ذاكرة الوصول العشوائي، يتخلصmemory.minمن أبرد% 10 فقط من كل برنامج خفي ويحتفظ بـSystemUIوsurfaceflingerوaudioserverعند الحد الأدنى البالغ% 90 بدون أي أخطاء مجهولة المصدر وبدون زيادة في إنهاء عملياتlmkd.
يوفّر memory.min حجزًا ماديًا قويًا يطابق حماية تثبيت PinnerService mlock الذي يحلّ محله، مع ميزة أنّ LRU للنواة (بدلاً من قائمة ملفات ثابتة) يختار صفحات الرموز البرمجية النشطة والكومة والرسومات التي تظل مقيمة.
الشكل 2: الاحتفاظ بمجموعة العمليات الخفية في ظل تزايد الضغط على الذاكرة
الإحماء المسبق لعملية التشغيل واستعادة ذاكرة التخزين المؤقت للملفات غير المعيّنة بعد التشغيل
يتطلب استبدال mlock الدائم لـ PinnerService في
config_defaultPinnerServiceFiles تنسيق سلوكين
في وقت التشغيل:
- التشغيل المُسبَق لعملية التشغيل في الخلفية لمرة واحدة (
PinnerService): يتم تخطّيPinnerServicemlockبدون تشغيل ذاكرة التخزين المؤقت للصفحة، ما يؤدي إلى نقل حوالي 95 ميغابايت منSystemUIAPK وODEX وVDEX إلى مسار التشغيل المتزامن عند بدء تشغيلSystemUI(OnBootPhase_550)، ما يضيف من 300 إلى 450 ملي ثانية إلى وقت اكتمال التشغيل. لا يكفي استدعاءmadvise(MADV_WILLNEED)لأنّforce_page_cache_raفي النواة يثبّت استدعاءMADV_WILLNEEDواحدًا في نافذة قراءة مسبقة واحدة (عادةً من 128 كيلوبايت إلى 2 ميغابايت). بدلاً من ذلك، عندما يكونSystemMemoryBudgetManager.shouldSkipDefaultSystemPinningنشطًا، يربطPinnerServiceكل ملف فيconfig_defaultPinnerServiceFilesبسلسلة مهام في الخلفية أثناءonStart، ويملأ الملف بشكل متزامن في ذاكرة التخزين المؤقت للصفحة باستخدامOs.mlock، ويستدعي على الفورOs.munlockوmunmapوclose. يحافظ ذلك على وقت التشغيل السريع مع ترك صفر بايت مقفل بشكل دائم حتى يمكن إزالة صفحات بدء التشغيل على البارد لاحقًا. - استبعاد ذاكرة التخزين المؤقت لفحص حِزم التشغيل في
system_serverواستعادتها: أثناء التشغيل، يفحصPackageManagerServiceملفات APK المثبَّتة، ما يترك من 1.5 إلى 2.5 غيغابايت من ذاكرة التخزين المؤقت لصفحات الملفات غير المعيّنة التي يتم تحميلها إلى مجموعة التحكّم (cgroup) فيsystem_server. إذا تم تضمينها في عملية حسابmemory.minلـsystem_server، فإنّ ذاكرة التخزين المؤقت للتشغيل العادي تستنفد الحد الأقصى العام لذاكرة الوصول العشوائي (RAM) الذي يبلغ% 10 وتخفّض بشكل متناسب الحدود الدنيا للحماية فيsurfaceflingerوSystemUIوaudioserver. لتجنُّب مشكلة نقص الحد الأقصى، يقرأSystemMemoryBudgetManagermemory.statلـsystem_server، ويحسب ذاكرة التخزين المؤقت للملفات غير المرتبطة على أنّهاmax(0, file - shmem - file_mapped)، ويطرح ذاكرة التخزين المؤقت غير المرتبطة منmemory.currentقبل حساب الحد الأدنى البالغ% 90، كما هو موضّح في الشكل 3. بالإضافة إلى ذلك، بعد 10 ثوانٍ منPHASE_BOOT_COMPLETED، ينفّذ المدير عملية كتابة لمرة واحدة لـ<unmapped_file> swappiness=0في عقدةmemory.reclaimمنsystem_serverعلى Linux 6.2 والنواة الأحدث لإزالة ذاكرة التخزين المؤقت لفحص الحزمة غير النشطة بشكل استباقي بدون تبديل الذاكرة الديناميكية المجهولة أو إزالة صفحات DEX والرموز التي تم ربطها. في النواة القديمة (مثلandroid14-6.1) التي ترفضswappiness=0معEINVAL، يتخطّى المدير عملية كتابةmemory.reclaimبدلاً من الرجوع إلى عملية كتابة غير مؤهَّلة لاستعادة المساحة، والتي من شأنها تبديل كومة الذاكرة المؤقتة المجهولة أثناء التشغيل.
الشكل 3: تقارب الحد الأدنى للحماية واستعادة ذاكرة التخزين المؤقت بعد التشغيل
متطلبات النواة وتراكبات إعدادات الجهاز
يعتمد SystemMemoryBudgetManager على mem_cgroup_calculate_protection في نواة Linux لنشر memory.min عبر مجموعات التحكم المُدمجة. تتضمّن نواة Android الشائعة android15-6.6 وandroid16-6.12 دعمًا كاملاً للحماية المتداخلة من خلال MGLRU. تتطلّب الأجهزة التي تعمل بنظام التشغيل android14-6.1 مع تفعيل ميزة MGLRU ثلاثة منافذ خلفية في mm/vmscan.c وmm/memcontrol.c، بحيث تنشر مجموعات التحكم (cgroups) الفارغة في الشرائح المتوسطة ومعرّفات UID الحماية إلى مجموعات التحكم (cgroups) في عمليات الأوراق:
-
30d77b7eef01(mm/mglru: fix ineffective protection calculation) -
8aa420617918(mm/mglru: respect min_ttl_ms with memcgs) -
adb8213014b2(mm: memcg: fix stale protection of reclaim target memcg)
يمكن للمصنّعين الأصليين للأجهزة تخصيص ميزة "SystemMemoryBudgetManager" أو إيقافها باستخدام
تراكبات موارد إطار العمل التالية:
-
config_systemMemoryBudgetLowKb(عدد صحيح، كيلوبايت): يحدّد0(تلقائي) مجموع جميع الحدود الدنيا لـmemory.minعند% 10 من إجمالي ذاكرة الوصول العشوائي (RAM) الفعلية. تؤدي القيمة الموجبة إلى ضبط حد أقصى صريح بالكيلوبايت، بينما تؤدي القيمة السالبة إلى إيقافSystemMemoryBudgetManagerعلى الجهاز (مع الاحتفاظ بتثبيتmlockالثابت القديم فيPinnerService). -
config_systemMemoryBudgetHighKb(عدد صحيح، كيلوبايت):0(تلقائي) يترك/sys/fs/cgroup/system/memory.highعندmax. تحدّد القيمة الموجبة الحد الأقصى للشريحة العلياmemory.high(يجب أن تكون أكبر من أو تساوي الحد الأدنى للسعر).
config_systemMemoryBudgetAdditionalSystemProcesses(مصفوفة السلاسل النصية): تعرض أسماء العمليات الخفية الإضافية للنظام الأصلي أو المورّد التي تتأثر بوقت الاستجابة في/sys/fs/cgroup/system(تتم مطابقتها مع/proc/<pid>/commأو الاسم الأساسي لـargv[0]في/proc/<pid>/cmdlineلمعرّفات المستخدمين للنظام والمورّد ضمن10000) لحمايتها باستخدام الحد الأدنى منmemory.minبنسبة% 90 إلى جانب العمليات الخفية الست التلقائية للنظام. استخدِم هذا التراكب بدلاً من ضبطmemory.minفيinit.rcلأنّSystemMemoryBudgetManagerيعيد احتسابuid_<uid>/memory.minكمجموع عمليات الأوراق المُدارة ويمحو عُقدuid_*غير المُدارة عند كل إعادة تحميل. على سبيل المثال، يمكن لجهاز XR حماية برامج تتبُّع المواقع المكانية وبرامج HAL للكاميرا باستخدام التراكب التالي:<string-array translatable="false" name="config_systemMemoryBudgetAdditionalSystemProcesses"> <item>android.hardware.perceptionhost</item> <item>auracamerahal</item> </string-array>
config_systemUi(سلسلة): اسم حزمة تطبيق SystemUI للنظام الأساسي، يتم حله باستخدامMATCH_SYSTEM_ONLY.
لفحص عُقد SystemMemoryBudgetManager floors وcgroup النشطة على
جهاز، شغِّل:
# Inspect policy state, resolved PIDs, and applied floors in dumpsys meminfo adb shell dumpsys meminfo | sed -n '/System Memory Budgets/,$p'# Inspect raw cgroup v2 memory.min nodes across the system and apps slices adb shell head -n 1 \ /sys/fs/cgroup/system/memory.min \ /sys/fs/cgroup/system/uid_*/memory.min \ /sys/fs/cgroup/system/uid_*/pid_*/memory.min \ /sys/fs/cgroup/apps/memory.min \ /sys/fs/cgroup/apps/uid_*/memory.min \ /sys/fs/cgroup/apps/uid_*/pid_*/memory.min
ربط تطبيقات النظام الثابتة والتي تعمل في الخلفية بميزانيات الذاكرة
على الرغم من أنّ SystemMemoryBudgetManager يحمي برامج الخلفية التفاعلية من استعادة الموارد
باستخدام الحد الأدنى من memory.min، فإنّ العديد من تطبيقات النظام الأخرى وخدمات النظام الأساسي
المميّزة تعمل في الخلفية لفترات طويلة كعمليات PERSISTENT
أو خدمات تعمل في المقدّمة أو أدوات توفير المحتوى التي يتم الاستعلام عنها بشكل متكرر.
بدون حدود قصوى صريحة للذاكرة، لا يتم تقييد هذه العمليات إلى أن تصل إلى حدود محدِّد الذاكرة التي تبلغ عدة غيغابايت (مثل 4 غيغابايت إلى 10 غيغابايت للتطبيقات المرئية و2 غيغابايت إلى 5 غيغابايت للتطبيقات التي تعمل في الخلفية) أو إلى أن يؤدي الضغط العام على الذاكرة إلى تشغيل نشاط kswapd و"أداة إنهاء العمليات عند انخفاض الذاكرة" (lmkd) على مستوى النظام.
إذا لم يتم تقييد عمليات النظام في الخلفية، فإنّها غالبًا ما تجمّع كميات كبيرة من الذاكرة غير المستخدَمة التي لا تشكّل جزءًا من مجموعة العمل النشطة:
- ذاكرة التخزين المؤقت لصفحات الملفات غير المحدودة: الخدمات التي تفهرس الوسائط أو تبحث في قواعد البيانات أو تزامِن جداول التقويم ومقدّمي الخدمات (مثل
AppSearchوMediaProviderوCalendarProvider) ترسم خرائط أو تبث من خلال ملفات كبيرة على القرص. بدون حدّ أقصى لمجموعة التحكّمmemory.high، تظلّ الصفحات النظيفة المستندة إلى الملفات من عمليات القراءة لمرة واحدة تُحتسب ضمن مجموعة التحكّم للعملية إلى أجل غير مسمى، ما يستهلك مئات الميغابايت من ذاكرة الوصول العشوائي (RAM) الفعلية. - الاحتفاظ بالكومة المجهولة المصدر بعد الارتفاع المفاجئ: الخدمات التي تشهد ارتفاعات مفاجئة عابرة في النشاط، مثل
Bluetoothالارتفاعات المفاجئة في الصوت واكتشاف BLE، أوNetworkStackالتحقّق من صحة بروتوكول أمان طبقة النقل (TLS) للمدخل المشروط الوصول إليه، أو انتقال مساعدي واجهة المستخدم إلى الخلفية، يمكنها الاحتفاظ بصفحات الكومة المجهولة المصدر غير النشطة لفترة طويلة بعد اكتمال الارتفاع المفاجئ.
Applying calibrated <memory-budget> declarations (memory.high soft limits,
typically 30 MB to 190 MB) to system apps provides two primary
benefits:
- استعادة الصفحات بشكل استباقي ومحلي: عندما تتجاوز عملية النظام
ميزانية
memory.highالتي تم ضبطها، توجّه نواة Linux استعادة الصفحات تحديدًا إلى مجموعة التحكم هذه، وتطرد الصفحات الباردة المدعومة بالملفات أولاً وتضغط الصفحات المجهولة غير النشطة إلى ZRAM بدون انتظار ضغط ذاكرة الجهاز العامة. - توفير المزيد من ذاكرة الوصول العشوائي (RAM) للتطبيقات التي تعمل في المقدّمة ومجموعة التطبيقات المخزَّنة مؤقتًا: يؤدي تقييد ذاكرة التخزين المؤقت للملفات غير النشطة في خدمات النظام التي تعمل دائمًا إلى استعادة عشرات إلى مئات الميغابايت من ذاكرة الوصول العشوائي (RAM) الفعلية على الجهاز، ما يقلّل من تأخُّر واجهة المستخدم، ويخفّف الضغط على تشغيل الكاميرا، ويحافظ على نشاط المزيد من تطبيقات المستخدم في الحالة المخزَّنة مؤقتًا.
ضبط ميزانيات الذاكرة لتطبيقات النظام
تستخدم تطبيقات النظام بنية بيان <memory-budget> نفسها، وتتالي حالة العملية، وتغيير حجم كثافة العرض، وقاعدة حلّ عبارة المطابقة الأخيرة مثل التطبيقات العامة. للاطّلاع على القائمة الكاملة للسمات، يُرجى مراجعة مرجع سمات XML.
يمكن للمصنّعين الأصليين للأجهزة الإعلان عن عناصر <memory-budget> مباشرةً داخل ملف AndroidManifest.xml الخاص بتطبيق النظام أو دمجها من ملف XML منفصل باستخدام السمة additional_manifests في Android.bp. وفقًا للعرف، يخزّن مشروع Android المفتوح المصدر (AOSP)
ميزانيات تطبيقات النظام المرجعية في ملفات *-budget.xml مستقلة (إما في
frameworks/base/core/memory_budgets/ لحِزم المنصة الأساسية أو إلى جانب
الوحدات الفردية مثل packages/modules/NetworkStack/memory_budgets/
وpackages/modules/AppSearch/apk/ وpackages/services/Telephony/)
ويرفقها بـ additional_manifests:
android_app {
name: "TeleService",
manifest: "AndroidManifest.xml",
additional_manifests: ["Telephony-budget.xml"],
// ...
}
تحديد النطاق على مستوى الحزمة (UID) مقابل مستوى العملية (PID)
يحدّد ما إذا كنت تعلن عن ميزانية أساسية على مستوى الحزمة (<application>) أو ميزانية متعددة العمليات (<processes><process>) ما إذا كانت النواة تفرض memory.high على مستوى مجموعة التحكم في معرّف المستخدم (/sys/fs/cgroup/uid_<uid>/memory.high) أو على مستوى مجموعة التحكم في معرّف العملية (/sys/fs/cgroup/uid_<uid>/pid_<pid>/memory.high)، كما هو موضّح في الشكل 4:
- الحدّ الأقصى على مستوى الحزمة (
<application>): يُستخدَم عندما يشغّل ملف APK عملية واحدة ضمن معرّف UID مخصّص له (على سبيل المثال،BluetoothأوNfcأوNetworkStackأوCalendarProviderأوTraceurأوAppSearch). - الحدّ الأقصى المسموح به على مستوى العملية (
<processes><process>): يُستخدَم عندما تشارك حزمة APKandroid:sharedUserId(مثلandroid.uid.phoneمع معرّف UID1001أوandroid.uid.systemمع معرّف UID1000) مع حِزم النظام الأخرى حتى لا يتم تقييد العمليات الأخرى التي تشارك معرّف UID هذا معًا، أو عندما تشغّل حزمة APK واحدة عمليات متعدّدة بأدوار ذاكرة مختلفة (على سبيل المثال، برنامج الخلفية الخفيMediaProviderوالعملية الفرعية لواجهة المستخدم:PhotoPicker).
الشكل 4. الحدود القصوى للذاكرة على مستوى UID مقابل مستوى PID
يوضّح المثال التالي MediaProvider-budget.xml، الذي يحدّد نطاق الميزانيات المستندة إلى ذاكرة الوصول العشوائي (RAM) لعملية MediaProvider التلقائية (<process>) وميزانية مستندة إلى حجم العرض لعملية واجهة المستخدم :PhotoPicker. تتطابق كل سمة android:maxDeviceRamMb مع الأجهزة التي يكون إجمالي ذاكرة الوصول العشوائي (RAM) الفعلية (MemTotal) فيها أقل من أو يساوي الحدّ الأدنى المحدّد بالميغابايت (أو تنطبق على أي سعة لذاكرة الوصول العشوائي عند حذفها). يتم ترتيب البنود من التلقائي غير المقيّد
إلى أصغر حدّ maxDeviceRamMb بحيث تختار
قاعدة حلّ البند الأخير المطابق
أضيق فئة تنطبق:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.providers.media.module">
<uses-sdk android:targetSdkVersion="10000" />
<application>
<processes>
<process>
<memory-budget
android:maxMb="85" />
<memory-budget
android:maxMb="75"
android:maxDeviceRamMb="12288" />
<memory-budget
android:maxMb="60"
android:maxDeviceRamMb="8192" />
</process>
<process android:process=":PhotoPicker">
<memory-budget
android:maxMb="85"
android:additionalBytesPerDisplayPixel="25" />
</process>
</processes>
</application>
</manifest>
كيفية معايرة الميزانيات المرجعية لنظام Android المفتوح المصدر (AOSP) على أجهزة Google Pixel
تمت معايرة ميزانيات ذاكرة تطبيقات النظام المرجعية في مشروع Android المفتوح المصدر (AOSP) على مستوى أجهزة Google Pixel التي تتراوح سعة ذاكرة الوصول العشوائي (RAM) الفعلية فيها بين 6 غيغابايت و16 غيغابايت (بما في ذلك الهواتف والأجهزة القابلة للطي والأجهزة اللوحية بسعة 6 غيغابايت و8 غيغابايت و12 غيغابايت و16 غيغابايت) ودقة العرض التي تتراوح بين 1.2 ميغابكسل تقريبًا (720×1600) و4.5 ميغابكسل تقريبًا (2076×2152).
جمعت المعايرة بين مصدرَي بيانات متكاملَين: بيانات القياس عن بُعد على مستوى الأسطول في حقل cgroup v2، وعمليات فحص memory.high للأجهزة الفعلية الخاضعة للتحكّم في رحلات المستخدم الأساسية (CUJ).
تحليل بيانات القياس عن بُعد في cgroup v2 على مستوى الأسطول
تم جمع لقطات دورية من الإصدار الثاني من cgroup من جميع الأجهزة وتقسيمها
حسب فئة ذاكرة الوصول العشوائي (RAM) الفعلية (أقل من أو تساوي 8 غيغابايت، و12 غيغابايت، وأكبر من أو تساوي 16 غيغابايت) ومجموعة
حالة العملية (foreground وperceptible وbackground وcached). تم الاستناد إلى ستة
مبادئ في التحليل الإحصائي:
- تقسيم
memory.currentإلى مجموعة عمل مقابل ذاكرة تخزين مؤقت للملفات قابلة للاسترداد: بما أنّmemory.highيتحكّم في شحن مجموعة التحكم (cgroup) المقيمة (memory.current)، تم تقسيم كل لقطة باستخدامmemory.statإلى كومة مجهولة (anon)، وصفحات مجهولة تم تبديلها (swap)، وذاكرة تخزين مؤقت للصفحات المستندة إلى الملفات (file)، كما هو موضّح في الشكل 5. يحدّد إجمالي الطلب المجهول غير القابل للضغط (anon + swapفي P99) الحد الأدنى لمجموعة العمل للميزانية حتى لا تتعرّض العملية لخطر استنفاد ZRAM، بينما تشير الفجوة الكبيرة بينmemory.currentP99 وanon + swapP99 إلى ذاكرة التخزين المؤقت لصفحة الملف التي يمكن لـmemory.highاستردادها، بشرط أن تكون ذاكرة التخزين المؤقت غير معيّنة وغير نشطة. - مراعاة الذاكرة التي لا يمكن لـ "
memory.high" استعادتها: ليست كل الملفات والذاكرة المشتركة عبارة عن ذاكرة تخزين مؤقت غير نشطة. الصفحات المقفلة (unevictableفيmemory.stat، مثل الذاكرة المشتركة المقفلة باستخدامmlockأو ذاكرة الوصول العشوائي (RAM) المقفلة للضيف في جهاز افتراضي يتم تحميل عمليات المضيف الخاصة به على مجموعة التحكم (cgroup) الخاصة بالتطبيق) تضع حدًا أدنى صارمًا ضمن الميزانية، وغالبًا ما تكون الصفحات المعيّنة (file_mapped) جزءًا من مجموعة العمل النشطة. يُرجى التحقّق منunevictableوshmemوfile_mappedقبل التعامل مع ذاكرة الملفات على أنّها قابلة للاسترداد. على سبيل المثال، يتم قفل حوالي 100 ميغابايت من ذاكرةAppSearchولا يمكن إخلاؤها، لذا تغطي ميزانيتها هذا الحد الأدنى بالإضافة إلى مجموعة العمل المضيفة النشطة، مع توفير مساحة لنمو المنطقة المقفلة. - فلترة التخفيف في حالة عدم النشاط: تقضي أدوات توفير المحتوى (
CalendarProvider) وأدوات المطوّرين عند الطلب (Traceur) من% 70 إلى% 99.9 من لقطات المجال في حالة عدم النشاط عند حجم يتراوح بين 1 ميغابايت و3 ميغابايت تقريبًا. يؤدي احتساب النسب المئوية الأولية في جميع اللقطات إلى تقليل تقديرات P95 وP99 بشكل كبير. بدلاً من ذلك، تم احتساب النسب المئوية وفواصل الثقة على اللقطات النشطة غير المخففة (مع استبعاد لقطاتCACHEDواللقطات المرجعية غير النشطة). - استخدام فواصل الثقة المجمّعة حسب الجهاز: نظرًا لأنّ الجهاز الواحد يساهم في العديد من اللقطات الدورية بمرور الوقت، فإنّ التعامل مع اللقطات كعيّنات مستقلة يقلل من عدم اليقين في الذيل. تم تقييم جميع تقديرات مجموعة العمل P95 وP99 باستخدام فواصل ثقة متحفظة بنسبة %95 مجمّعة حسب الجهاز (باستخدام عدد الأجهزة المميّزة
N_devكحجم العينة الفعلي). - مراعاة الارتفاعات المفاجئة المؤقتة في استخدام الذاكرة من خلال
memory.peak: قد لا ترصد عملية أخذ العينات الدورية الارتفاعات المفاجئة القصيرة الأجل في استخدام الذاكرة (مثلNetworkStackعملية التحقّق من بروتوكول أمان طبقة النقل (TLS) في المدخل المشروط الوصول إليه وعمليات فحص نظام أسماء النطاقات المتزامنة، أوBluetoothعملية إعداد ملف توزيع الصوت المتقدّم (A2DP) وتكنولوجيا BLE). بالنسبة إلى الخدمات التي تتطلّب موارد كثيرة، تم تحديد حجم الميزانيات لتغطية الشريحة المئوية من 90 إلى 95 من الحد الأقصى لاستخدامmemory.peakفي النواة طوال فترة الاستخدام على مستوى فئات ذاكرة الوصول العشوائي. - تأكَّد من أنّ فئة ذاكرة الوصول العشوائي (RAM) تعكس ذاكرة الوصول العشوائي، وليس جيل الجهاز: تميل الأجهزة الأحدث إلى أن تحتوي على المزيد من ذاكرة الوصول العشوائي والمزيد من الميزات، لذا فإنّ مجموعة العمل التي تزداد مع فئة ذاكرة الوصول العشوائي قد تزداد في الواقع مع الميزات. قبل إضافة فئة
maxDeviceRamMb، يمكنك تقسيم البيانات حسب طراز الجهاز. على سبيل المثال، يصل تطبيق "com.android.phone" إلى قيمة P99 نفسها في "anon + swap" (من 85 إلى 90 ميغابايت تقريبًا) على الهواتف التي تتضمّن ذاكرة وصول عشوائي بسعة 12 غيغابايت و16 غيغابايت من الجيل نفسه، بينما يستخدم هاتف قديم قابل للطي يتضمّن ذاكرة وصول عشوائي بسعة 12 غيغابايت 40 ميغابايت. وبالتالي، تستخدم ميزانيتها قيمة واحدة بدون فئة ذاكرة وصول عشوائي (RAM)، حتى لا يتم تخصيص ميزانية أقل من اللازم لجهاز مزوّد بذاكرة وصول عشوائي أقل ويوفّر ميزات الاتصال الهاتفي الأحدث.
الشكل 5: مجموعة العمل مقابل ذاكرة التخزين المؤقت للملفات القابلة للاسترداد
رحلة المستخدم الأساسية (CUJ) على الجهاز الفعلي وعمليات فحص تغيير حجم العرض
للتحقّق من صحة الميزانيات المستمَدة من بيانات القياس عن بُعد ومعايرة الميزانيات
المتناسبة مع الشاشة (مثل :PhotoPicker) والميزانيات المخصّصة للخلفية حسب الحالة (مثل
Traceur)، تم تنفيذ عمليات فحص memory.high مباشرة على أجهزة فعلية تتراوح سعة ذاكرة الوصول العشوائي (RAM) فيها بين
6 غيغابايت و16 غيغابايت:
- العثور على نقطة الانحناء التي لا تتضمّن أخطاء في الذاكرة: أثناء تشغيل رحلات المستخدمين المهمة الشاملة (مثل
التمرير السريع لشبكة الصور وتصفُّح الألبومات والتمرير السريع لمعاينة الصور والفيديوهات
بدقة عالية في وضع ملء الشاشة وتسجيل عمليات التتبُّع وحفظها)، تم خفض
memory.highأثناء قياس عدّاداتmemory.statلمجموعة التحكم (workingset_refault_anonوworkingset_refault_fileوpgscanوpgsteal) وmemory.events(high). كما هو موضّح في الشكل 6، تقع الميزانية المثالية فوق نقطة الانحناء التي لا تتضمّن أخطاء في الذاكرة مباشرةً. نقطة الانحناء لعدم حدوث أخطاء في الذاكرة هي الحدّ الذي تستعيد عنده النواة ذاكرة التخزين المؤقت للملفات غير النشطة التي يتم استخدامها لمرة واحدة (pgsteal > 0) بدون بدء عملية تبديل نشطة لمجموعة العمل (workingset_refault == 0). - التحقّق من صحة تغيير حجم بكسل الشاشة على مستوى درجات الدقة: أكّد الاختبار
:PhotoPickerعلى مستوى أربع درجات دقة شاشة فعلية ومحاكاة من ~1.2 ميغا بكسل (720×1600) إلى ~4.5 ميغا بكسل (2076×2152 شاشة داخلية غير مطوية) أنّ مجموعة العمل النشطة لصور Glide وViewPager2 النقطية تتغيّر بشكل خطي مع عدد بكسل الشاشة. يختلف أيضًا الحدّ الأساسي لعدم العرض حسب الجهاز: عند عدد وحدات البكسل نفسه تقريبًا، كان الحدّ الأدنى لعدم إعادة التحميل حوالي 140 ميغابايت على الشاشة الخارجية لجهاز قابل للطي بسعة 16 غيغابايت مقابل 110 إلى 125 ميغابايت على هاتف بسعة 6 غيغابايت. يظل الحد الأدنى البالغ 85 ميغابايت بالإضافة إلى 25 بايت لكل بكسل في الشاشة (android:maxMb="85"وandroid:additionalBytesPerDisplayPixel="25") أعلى من نقطة الانحناء التي تم قياسها على كل شاشة تم اختبارها (حوالي 110 ميغابايت على شاشات HD+ وحوالي 145 ميغابايت على شاشات FHD+ وحوالي 190 ميغابايت على الشاشات غير المطوية). - التحقّق من عملية "تجميع الموارد غير الصالحة" في وقت تشغيل Android في حالات الخلفية: في الإصدار الثاني من cgroup،
تظل صفحات صور إطار العمل و
boot.artالتي تتم مشاركتها من خلال Zygote مشحونة إلى cgroup في Zygote ويتم التعامل معها كمساحة محصّنة أثناء عملية "تجميع الموارد غير الصالحة" المتزامنة في وقت تشغيل Android. أكّد اختبار الضغط أنّه عندما ينتقل تطبيق واجهة مستخدم النظام إلىbackground، فإنّ تضييقmemory.high(على سبيل المثال، إلى 30 ميغابايت علىTraceur) يحدّ بشكل واضح من الذاكرة الديناميكية الخاصة وذاكرة التخزين المؤقت للصفحة بدون التسبّب في حدوث تكرار في تجميع المهملات أو نشاط المبادلة.
الشكل 6: العثور على نقطة الانحناء التي لا تتضمّن أي أخطاء في الذاكرة أثناء رحلة المستخدم الأساسية
ملخّص ميزانيات تطبيقات النظام المرجعية في مشروع Android المفتوح المصدر (AOSP)
يلخّص الجدول التالي الميزانيات المرجعية التي تمت معايرتها في مشروع Android المفتوح المصدر (AOSP) على مستوى فئات ذاكرة الوصول العشوائي وحالات العمليات:
| حزمة أو عملية تابعة للنظام | النطاق | ذاكرة وصول عشوائي (RAM) بسعة 8 غيغابايت أو أقل | ذاكرة وصول عشوائي (RAM) بسعة 12 غيغابايت | ذاكرة وصول عشوائي (RAM) بسعة 16 غيغابايت أو أكثر | برنامج التشغيل الأساسي للمعايرة |
|---|---|---|---|---|---|
com.android.bluetooth |
رقم التعريف الفريد (<application>) |
80 ميغابايت | 95 ميغابايت | 110 ميغابايت | يغطي هذا الإذن عمليات الاندفاع في memory.peak خلال عمر P90 (من 75 إلى 110 ميغابايت تقريبًا) و >2x من memory.current النشط في P99. |
com.android.nfc |
UID (<application>) |
50 ميغابايت | 60 ميغابايت | 60 ميغابايت | تغطي هذه الميزة وظيفة محاكاة البطاقة المُضيفة النشطة P99 (ما يصل إلى 50 ميغابايت تقريبًا) وP90 إلى P95 memory.peak أثناء تقليص ذاكرة التخزين المؤقت للملفات غير النشطة. |
com.android.providers.calendar |
UID (<application>) |
70 ميغابايت تلقائيًا (في المقدّمة) 50 ميغابايت في perceptible وbackground |
مجموعة العمل النشطة لا تتغيّر في جميع فئات ذاكرة الوصول العشوائي (RAM). تحتفظ ميزانية الخلفية بمساحة تخزين مجهولة الهوية للتنبيهات التذكيرية أثناء تقليص ذاكرة التخزين المؤقت لصفحة SQLite أثناء المزامنة. | ||
com.android.traceur |
رقم التعريف الفريد (<application>) |
85 ميغابايت تلقائيًا (في المقدّمة ويمكن ملاحظته) 30 ميغابايت background |
يحافظ على مساحة تخزين كاملة تبلغ 85 ميغابايت أثناء تسجيل التتبُّع النشط وتصديره (TraceService)، مع تحديد الحد الأقصى لحالة عدم النشاط والبث عند 30 ميغابايت. |
||
com.android.providers.media.module (الرئيسي) |
رقم تعريف المنتج (<process>) |
60 ميغابايت | 75 ميغابايت | 85 ميغابايت | توفير مساحة تخزين تتراوح بين 10 و30 ميغابايت تقريبًا على P99 anon + swap أثناء استرداد ذاكرة التخزين المؤقت لملفات SQLite والصور المصغّرة غير المستخدَمة |
com.android.providers.media.module:PhotoPicker |
رقم تعريف المنتج (<process>) |
85 ميغابايت + 25 بايت لكل بكسل (~110 ميغابايت على شاشة HD+، و~145 ميغابايت على شاشة FHD+، و~190 ميغابايت على شاشة قابلة للطي بدقة ~4.5 ميغابكسل) |
يتم تغيير الحجم بشكل متناسب مع عدد وحدات البكسل في الشاشة (additionalBytesPerDisplayPixel="25") ليتطابق مع نقطة الانحناء في مجموعة العمل الخاصة بالصورة النقطية في Glide. |
||
com.android.networkstack |
رقم التعريف الفريد (<application>) |
65 ميغابايت | 70 ميغابايت | 85 ميغابايت | ذاكرة مجهولة الهوية في الغالب، بحجم P95 مدى الحياة memory.peak لتغطية بروتوكول أمان طبقة النقل (TLS) ونظام أسماء النطاقات (DNS) وبروتوكول الإعداد الديناميكي للمضيف (DHCP) في المدخل المشروط الوصول إليه. |
com.android.appsearch.apk |
رقم التعريف الفريد (<application>) |
130 ميغابايت | يغطي هذا الخيار حوالي 100 ميغابايت من الذاكرة المقفلة وغير القابلة للإخلاء، بالإضافة إلى مجموعة عمل مضيف نشطة تبلغ حوالي 5 ميغابايت، مع توفير مساحة إضافية لنمو المنطقة المقفلة. تم قياس صفر أخطاء في إعادة التحميل عند ≥125 ميغابايت أثناء استرداد ذاكرة التخزين المؤقت للصفحات غير النشطة (ما يصل إلى 330 ميغابايت تقريبًا في المئوية 99). | ||
com.android.phone (TeleService) |
رقم تعريف المنتج (<process>) |
120 ميغابايت | يتم تحديد نطاق كل معرّف PID على معرّف UID المشترك 1001. تتتبّع مجموعة العمل جيل الجهاز بدلاً من ذاكرة الوصول العشوائي (RAM)، لذا تزيد الميزانية الواحدة بمقدار 30 ميغابايت تقريبًا عن أعلى قيمة anon + swap في الشريحة المئوية 99 لكل طراز. |
||
كيف يمكن للمصنّعين الأصليين للأجهزة إعادة معايرة ميزانيات تطبيقات النظام لأجهزتهم؟
يمكن للمصنّعين الأصليين للأجهزة الذين يخصّصون تطبيقات النظام (على سبيل المثال، إضافة ملفات تعريف بلوتوث خاصة بالمورّدين أو إضافات هاتفية مخصّصة أو مفهرسات وسائط خاصة بالمصنّعين الأصليين للأجهزة) أو يشحنون خدمات نظام إضافية مثبّتة مسبقًا إعادة معايرة الميزانيات الحالية أو إنشاء ملفات *-budget.xml جديدة لمجموعة أجهزتهم.
جمع الملفات الشخصية النشطة لذاكرة cgroup v2
بالنسبة إلى كل عملية في النظام المستهدَف، اقرأ عُقد الذاكرة cgroup v2 ضمن
/sys/fs/cgroup/uid_<uid>/pid_<pid>/ في أعباء العمل التمثيلية ومستويات
ذاكرة الوصول العشوائي:
memory.current: الذاكرة المقيمة الحالية التي تم تحميلها إلى مجموعة التحكم (باستثناء الصفحات التي تمت مشاركتها مع Zygote)-
memory.peak: الحد الأقصى لعدد عملياتmemory.currentمنذ بدء العملية -
memory.swap.current: الاستخدام الحالي لملف المبادلة المضغوط في ZRAM memory.stat: تفاصيلanonوfileوpgscanوpgstealوworkingset_refault_anonوworkingset_refault_filememory.events: العدد التراكمي لانتهاكاتhigh(memory.highأحداث التقييد والاسترداد)
عند تجميع بيانات القياس عن بُعد من أجهزة الاختبار الداخلي أو الأجهزة الميدانية، افصل حالات
العمليات النشطة (TOP وFOREGROUND_SERVICE وعمليات الربط النشطة وعمليات المزامنة النشطة)
عن حالات CACHED غير النشطة أو حالات PERSISTENT غير النشطة حتى لا تؤدي اللقطات غير النشطة إلى انحراف
حسابات مجموعة العمل P95 وP99 إلى الأسفل.
فصل الذاكرة الديناميكية غير القابلة للضغط عن ذاكرة التخزين المؤقت للملفات القابلة للاسترداد
قارِن الشريحة المئوية التاسعة والتسعين من anon + swap بالشريحة المئوية التاسعة والتسعين من
memory.current:
- الخدمات التي تهيمن عليها ذاكرة التخزين المؤقت للملفات (
file≫anon، مثل موفّري قواعد البيانات وفهارس البحث وبرامج تسجيل الدخول): اضبطandroid:maxMbلتوفير مساحة مريحة (عادةً من 1.5 إلى 4 أضعاف) على P99anon + swapبالإضافة إلى نافذة عمل لصفحات الملفات النشطة. يتيح هذا الإعداد للنواة إخلاء صفحات الملفات غير المعيّنة الباردة باستمرار بدون لمس الذاكرة الديناميكية المجهولة. إذا كان حجمunevictableأوfile_mappedكبيرًا (كما هو الحال مع الذاكرة المقفلة أو قواعد البيانات المعيّنة في الذاكرة)، يتم احتساب هذه المساحة كمجموعة عمل أيضًا. - الخدمات التي يغلب عليها استخدام الذاكرة المؤقتة المجهولة أو الخدمات المتقطعة (يشكّل
anonمعظمmemory.current، مثل حِزم الشبكات أو الاتصال): يجب ضبط حجمandroid:maxMbلتغطية P90 إلى P95 منmemory.peakحتى لا تؤدي الاندفاعات العابرة إلى تشغيل عملية تبديل ZRAM المتزامنة على سلاسل المحادثات الحساسة لزمن الاستجابة. - عمليات واجهة المستخدم التي تعتمد بشكل كبير على العرض (مثل أدوات الاختيار أو المعارض أو أدوات مساعدة واجهة المستخدم في النظام): يمكنك قياس المساحة الأساسية غير المخصّصة لواجهة المستخدم والمساحة المتزايدة للصور النقطية لكل ميغابكسل على الشاشات ذات الدقة الأدنى والأعلى، والتعبير عن الميزانية باستخدام
android:maxMbبالإضافة إلىandroid:additionalBytesPerDisplayPixel.
تنظيف memory.high على الأجهزة الفعلية
قبل تخصيص ميزانية جديدة للإصدار، استخدِم am memory-limiter manual (أو
اكتب مباشرةً في عقدة مجموعة التحكّم memory.high للعملية في إصدار userdebug)
لاختبار الحدود المرشحة أثناء إجراء اختبارات CUJ الآلية:
# Override memory.high for a specific PID to 60 MB during a CUJ test
adb shell am memory-limiter manual <PID> 60MBمراقبة memory.stat وmemory.events قبل رحلة المستخدم الأساسية (CUJ) وبعدها:
- الميزانية منخفضة جدًا: يرتفع معدّل استخدام
workingset_refault_anonأوworkingset_refault_fileبشكل حاد أثناء رحلة المستخدم الأساسية، أوmemory.swap.currentيزداد معدّل الاستخدام باستمرار أثناء العمل النشط في المقدّمة، أو يتراجع وقت استجابة Binder أو إطار رحلة المستخدم الأساسية. زيادة الميزانية بعد نقطة الانحناء التلقائية - الميزانية مرتفعة جدًا: يظل
memory.events:high0حتى بعد أعباء العمل الثقيلة المتعلقة بالوصول المباشر إلى الملفات أو الفهرسة، وينموfileفيmemory.statبشكل غير محدود مع الصفحات الباردة. يجب تقليل الميزانية المخصّصة لمجموعة العمل النشطة. - الميزانية مضبوطة بشكل جيد: تظل قيمة
memory.currentفي الحالة الثابتة أقل منmemory.highأثناء التشغيل العادي. أثناء عمليات نقل الملفات الكبيرة أو عمليات التخزين المؤقت، يستعيدpgstealصفحات الملفات غير النشطة بينما يظلworkingset_refault_anonقريبًا من الصفر ولا يتغيّر وقت استجابة CUJ.