در Android 17 و نسخههای بالاتر، پلاتفرم حافظه فرایند سیستم را بااستفاده از دو سازوکار مکمل Linux cgroup v2 که درکنار محدودکننده حافظه عمومی برنامه کار میکنند مدیریت میکند:
- کفهای محافظت از دیمون سیستم (
SystemMemoryBudgetManagerباmemory.min): رزروهای خودتنظیم cgroup v2memory.min(تنظیمشده روی ۹۰٪ از مجموعه کاری مقیم مستقر هر دیمون و محدودشده در سطح جهانی به ۱۰٪ از کل RAM فیزیکی) از دیمونهای تعاملی حیاتی و فرایندهای پوسته (system_server،surfaceflinger، گرافیکcomposerHAL،audioserver،cameraserver،netd،SystemUI، و راهانداز Home) تحت فشار حافظه محافظت میکند و جایگزین سنجاق کردن فایلPinnerServicemlockایستا میشود. - سقف حافظه برنامه سیستم (
<memory-budget>باmemory.high): محدودیتهای نرم cgroup v2memory.highکالیبرهشده با حجم کاری (معمولاً ۳۰ مگابایت تا ۱۹۰ مگابایت) که در فایلهای مانیفست برای برنامههای سیستم پسزمینه و دائمی (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) |
| مدل اندازهگیری | خودتنظیمی در زمان اجرا (۹۰٪ از مجموعه کاری ثابت، با سقف جهانی ۱۰٪ از کل RAM) بدون جدولهای تنظیم برای هر دستگاه | مشخصههای XML مانیفست <memory-budget> اعلانی که براساس سطح RAM، وضعیت پردازش، و تعداد پیکسلهای نمایشگر کالیبره شدهاند |
| مزیت اصلی | از لرزش میانای کاربر تعاملی و توقفهای بیدار شدن تحت فشار حافظه جلوگیری میکند و درعینحال فهرستهای فایل PinnerService mlock ثابت را جایگزین میکند |
بهطور مداوم حافظه نهان فایل یکباره سرد و پشته پساز انفجار را تخلیه میکند تا RAM فیزیکی بیشتری برای برنامههای پیشزمینه و ذخیرهشده در حافظه نهان باقی بماند |
برای کسب اطلاعات بیشتر درباره نحو <memory-budget>، مشخصههای XML، میاناهای برنامهسازی کاربردی زمان اجرا، و حسابداری حافظه سیستمعامل، به تنظیم بودجه حافظه برنامه و درک و عیبیابی حافظه Android مراجعه کنید.
محافظت از دیمونهای تعاملی حیاتی با SystemMemoryBudgetManager
SystemMemoryBudgetManager فرایندهایی را که مستقیماً در مسیر تعاملی کاربر قرار دارند، درطول فشار حافظه در RAM فیزیکی نگه میدارد. SystemMemoryBudgetManager بهجای سنجاق کردن فهرست ثابتی از فایلهای APK، ODEX، و VDEX به حافظه با mlock (همانطور که PinnerService برای config_defaultPinnerServiceFiles و config_pinnerHomePinBytes انجام میدهد)، کفهای cgroup v2 پویا memory.min را به فرایندهای زیر اختصاص میدهد:
- برش سیستم اصلی (
/sys/fs/cgroup/system):system_server،surfaceflinger، گرافیکcomposerHAL،audioserver،cameraserver، وnetd، بهعلاوه هر سیستم بومی مختص فرم فاکتور یا دیمونهای فروشنده فهرستشده درconfig_systemMemoryBudgetAdditionalSystemProcesses(برای مثال،android.hardware.perceptionhostوauracamerahalدر دستگاههای XR). - برش برنامه تعاملی (
/sys/fs/cgroup/apps): فرایند اصلی بسته SystemUI پیکربندیشده (config_systemUi) و فرایند اصلی دارنده نقش «صفحه اصلی» کاربر فعلی.
محافظت از دارنده نقش Home درکنار config_systemUi پوشش را در همه ضریبهای شکل تضمین میکند. در عوامل فرمی که config_systemUi یک بسته سازگاری سبک است (مانند Wear OS، که صفحه ساعت، اعلانها، و کاشیها در داخل برنامه Home اجرا میشوند)، پوسته سمت کاربر همچنان محافظت کامل از مجموعه کاری را دریافت میکند. اگر Home intent به بسته config_systemUi منتهی شود، فرایند یکبار محافظت میشود. فقط فرایند اصلی
هر بسته (processName == packageName) کف محافظت دریافت میکند، بنابراین
فرایندهای فرعی کمکی (مثل :screenshot) بودجه محافظت را مصرف نمیکنند.
خطمشی تنظیم خودکار و واگذاری cgroup سه سطحی
ازآنجاییکه مجموعه کاری یک دیمون تعاملی در انواع مختلف دستگاهها و ظرفیتهای RAM بسیار متفاوت است (برای مثال، SystemUI حدود ۴۵ مگابایت در ساعت هوشمند، ۶۰ مگابایت در تلفن ۶ گیگابایتی، و ۱۸۰ مگابایت در تلفن ۱۶ گیگابایتی استفاده میکند)، جدولهای جستجوی ایستا برای هر دستگاه شکننده هستند. درعوض،
SystemMemoryBudgetManager کفها را مستقیماً از ردپای مقیم هر فرایند
بااستفاده از سه ثابت بهدست میآورد:
| پارامتر خطمشی | مقدار پیشفرض | رفتار |
|---|---|---|
| کف هر فرایند | ۹۰٪ از memory.current تسویهشده منهای حافظه نهان فایل نگاشتنشده |
از پشته ناشناس، اسلب، و کد نگاشتشده داغ محافظت میکند و درعینحال ۱۰٪ سردترین دنباله را قابلبازپسگیری میگذارد تا صفحههای واقعاً سرد همچنان بتوانند تخلیه شوند. حافظه نهان فایل نگاشتنشده (max(0, file - shmem - file_mapped) از memory.stat) قبلاز اعمال نسبت ۹۰٪ کسر میشود تا حافظه نهان اسکن بسته راهاندازی یا خواندن دارایی یکباره باعث افزایش کف نشود. |
| محدودیت کلی RAM | ۱۰٪ از کل RAM (config_systemMemoryBudgetLowKb) |
با حفاظ PinnerService config_pinnerMaxPinnedMemoryPercentage مطابقت دارد. اگر مجموع ۹۰٪ کفها از ۱۰٪ MemTotal بیشتر شود، هر کف بهطور متناسب با همان ضریب کاهش مییابد. |
| آهنگ بازآوری | ۱، ۴، ۱۶، و ۶۴ ثانیه پساز شروع، سپس هر ۳۰ دقیقه | یک سری هندسی ثابت بر روی مجموعه کاری پساز راهاندازی هر دیمون همگرا میشود، بدون اینکه تأخیرهای گرم کردن برای هر دستگاه بهصورت سختکدگذاری شده باشد، و یک بازآوری حالت پایدار ۳۰ دقیقهای رشد و کاهش تدریجی مجموعه کاری را در طول عمر دستگاه ردیابی میکند. |
در کنترلکننده حافظه Linux cgroup v2
(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، محافظت مطالبهنشده را بهطور متناسب بین همه شناسههای کاربری
و فرایندهای فرزند توزیع میکند (memory_recursiveprot)، که به فرایندهای تشخیصی
یا ثانویه که uid_1000 را همرسانی میکنند (android.uid.system) اجازه میدهد
محافظت را از surfaceflinger و audioserver بگیرند.
برای ارائه جداسازی دقیق برای هر دیمون، SystemMemoryBudgetManager
در هر بازآوری، در هر سه سطح سلسلهمراتب cgroup v2 محافظت مینویسد،
همانطور که در شکل ۱ نشان داده شده است:
- گره فرایند برگ (
pid_<pid>/memory.min): روی کف مجموعه کاری ۹۰٪ (مقیاسبندیشده) فرایند تنظیم شده است. - گره 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بازنشانی میشود.
شکل ۱. واگذاری کف محافظت سهسطحی در بخشهای cgroup.
چرا memory.min بهجای memory.low در هستههای MGLRU استفاده میشود
در Multi-Generational LRU (MGLRU، موتور بازیابی صفحه پیشفرض در هستههای Android نسخه ۶.۶ و جدیدتر)، memory.low و memory.min در mm/vmscan.c:shrink_one رفتار متفاوتی دارند:
memory.low(بهتعویق انداختن تکگذری): cgroup که استفاده آن کمتر ازmemory.lowاست به انتهای memcg LRU (MEMCG_LRU_TAIL) چرخانده میشود و برای یک گذر بازپسگیری رد میشود. در گذر بعدی تحت فشار حافظه پایدار، هسته cgroup را بهطور کامل بازیابی میکند و یک رویدادMEMCG_LOWرا ثبت میکند. در آزمایشهای فشار دستگاه فیزیکی با رشد حافظه ناشناس تا ۸۵٪ از حافظه دسترسی تصادفی فیزیکی،memory.lowبهSystemUIدر ساعت هوشمند اجازه داد از حدود ۴۵ مگابایت به حدود ۵ تا ۱۰ مگابایت کاهش یابد وaudioserverدر دستگاه تاشو ۱۶ گیگابایتی از ۱۵ مگابایت به ۲ مگابایت درمقابل حدود ۱۴ مگابایت کاهش یابد.memory.min(کف محافظت سخت): cgroup که استفاده آن کمتر ازmemory.minباشد، توسط بازیابی سراسری نادیده گرفته میشود. همانطور که در شکل ۲ نشان داده شده است، تحت همان حجم کاری فشار ۸۵٪ RAM،memory.minفقط سردترین ۱۰٪ دنباله هر دیمون را حذف میکند وSystemUI،surfaceflinger، وaudioserverرا در کف ۹۰٪ خود با صفر خطای مجدد ناشناس و بدون افزایش در پایان فرایندlmkdنگه میدارد.
memory.min یک رزرو فیزیکی سخت ارائه میدهد که با محافظت از سنجاق کردن PinnerService mlock که جایگزین آن میشود مطابقت دارد، با این مزیت که LRU هسته (بهجای فهرست فایلهای ایستا) انتخاب میکند کدام کد داغ، پشته، و صفحههای گرافیکی مقیم بمانند.
شکل ۲. حفظ مجموعه کاری Daemon تحت فشار فزاینده حافظه.
پیشگرم کردن راهاندازی و بازیابی حافظه نهان فایل نگاشتنشده پساز راهاندازی
جایگزین کردن PinnerService دائمی mlock
config_defaultPinnerServiceFiles مستلزم هماهنگ کردن دو رفتار
زمان راهاندازی است:
- پیشگرم کردن بوت پسزمینه یکباره (
PinnerService): رد شدنPinnerServicemlockبدون گرم کردن حافظه پنهان صفحه، حدود ۹۵ مگابایتSystemUIخواندن دیسک APK، ODEX، و VDEX را به مسیر بوت همگام منتقل میکند وقتیSystemUIشروع میشود (OnBootPhase_550)، ۳۰۰ تا ۴۵۰ میلیثانیه به تکمیل بوت اضافه میکند. فراخوانیmadvise(MADV_WILLNEED)کافی نیست زیراforce_page_cache_raدر هسته یک فراخوانیMADV_WILLNEEDرا به یک پنجره پیشخوان (معمولاً ۱۲۸ کیلوبایت تا ۲ مگابایت) محدود میکند. درعوض، وقتیSystemMemoryBudgetManager.shouldSkipDefaultSystemPinningفعال است،PinnerServiceهر فایل را درconfig_defaultPinnerServiceFilesروی یک رشته پسزمینه درطولonStartنگاشت میکند، فایل را بهطور همزمان باOs.mlockدر حافظه پنهان صفحه پر میکند، و بلافاصلهOs.munlock،munmap، وcloseرا فراخوانی میکند. این کار زمانبندی راهاندازی سریع را حفظ میکند و درعینحال بایتهای قفلشده دائمی را به صفر میرساند تا صفحات راهاندازی سرد بتوانند بعداً حذف شوند. - مستثنی کردن و بازپسگیری
system_serverحافظه نهان اسکن بسته راهاندازی: درطول راهاندازی،PackageManagerServiceفایلهای APK نصبشده را اسکن میکند و ۱٫۵ تا ۲٫۵ گیگابایت حافظه نهان صفحه فایل نگاشتنشده سرد را بهsystem_servercgroup اختصاص میدهد. اگر در محاسبهmemory.minازsystem_serverگنجانده شود، آن حافظه نهان راهاندازی سرد سقف ۱۰٪ حافظه دسترسی تصادفی سراسری را اشباع میکند و بهطور متناسب کفهای محافظتیsurfaceflinger،SystemUI، وaudioserverرا کاهش میدهد. برای جلوگیری از کمبود سقف،SystemMemoryBudgetManagermemory.statرا برایsystem_serverمیخواند، حافظه نهان فایل نگاشتنشده را بهصورتmax(0, file - shmem - file_mapped)محاسبه میکند، و آن حافظه نهان نگاشتنشده را ازmemory.currentقبلاز محاسبه کف ۹۰٪ کم میکند، همانطور که در شکل ۳ نشان داده شده است. علاوهبراین، ۱۰ ثانیه پسازPHASE_BOOT_COMPLETED، مدیر یکبار<unmapped_file> swappiness=0را در گرهmemory.reclaimازsystem_serverدر هستههای Linux 6.2 و جدیدتر مینویسد تا حافظه نهان اسکن بسته سرد را بدون جابهجایی توده ناشناس یا بیرون کردن DEX نگاشتشده و صفحههای کد بهطور پیشگیرانه بیرون کند. در هستههای قدیمیتر (مانندandroid14-6.1) کهswappiness=0را باEINVALرد میکنند، مدیر از نوشتنmemory.reclaimصرفنظر میکند و به نوشتن بازیابی نامشخصی که توده ناشناس را درطول راهاندازی مبادله میکند، برنمیگردد.
شکل ۳. همگرایی کف محافظت و بازیابی حافظه نهان پساز راهاندازی.
الزامات هسته و همپوشانیهای پیکربندی دستگاه
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 نیاز دارند تا گروههای کنترل UID و برش میانی خالی، محافظت را به گروههای کنترل فرایند برگ انتشار دهند:
-
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کف را به ۱۰٪ از کل RAM فیزیکی محدود میکند. مقدار مثبت سقف صریحی را برحسب کیلوبایت تنظیم میکند و مقدار منفیSystemMemoryBudgetManagerرا در دستگاه غیرفعال میکند (سنجاق کردنmlockایستایPinnerServiceقدیمی را حفظ میکند).config_systemMemoryBudgetHighKb(عدد صحیح، کیلوبایت):0(پیشفرض)/sys/fs/cgroup/system/memory.highرا درmaxباقی میگذارد. مقدار مثبت سقف برش بالاییmemory.highرا تنظیم میکند (باید بزرگتر یا مساوی با سقف کف باشد).config_systemMemoryBudgetAdditionalSystemProcesses(string-array): Lists additional latency-critical native system or vendor daemon process names in/sys/fs/cgroup/system(matched against/proc/<pid>/commor the basename ofargv[0]in/proc/<pid>/cmdlinefor system and vendor UIDs under10000) to protect with 90%memory.minfloors alongside the default six system daemons. از این همپوشانی بهجای تنظیمmemory.minدرinit.rcاستفاده کنید زیراSystemMemoryBudgetManageruid_<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،
سرویسهای پیشزمینه محدود، یا ارائهدهندگان محتوای مکرراً پرسوجوشده اجرا میشوند.
بدون سقف حافظه صریح، این فرایندها تا زمانی که به محدودیتهای چند گیگابایتی محدودکننده حافظه (مانند ۴ تا ۱۰ گیگابایت برای برنامههای قابلمشاهده و ۲ تا ۵ گیگابایت برای برنامههای پسزمینه) نرسند یا فشار حافظه سراسری باعث فعال شدن فعالیت kswapd در سراسر سیستم و حذفکننده حافظه کم (lmkd) نشود، محدود نمیشوند.
اگر پردازشهای سیستم پسزمینه بدون محدودیت رها شوند، اغلب مقدار زیادی حافظه سرد را که بخشی از مجموعه کاری فعال آنها نیست جمعآوری میکنند:
- حافظه نهان صفحه فایل نامحدود: سرویسهایی که رسانهها را نمایه میکنند، پایگاههای داده را جستجو میکنند،
یا تقویم و جدولهای ارائهدهنده را همگامسازی میکنند (مانند
AppSearch،MediaProvider، وCalendarProvider) ازطریق فایلهای بزرگ روی دیسک نگاشت یا جاریسازی میکنند. بدون سقف cgroupmemory.high، صفحات تمیز با پشتیبانی فایل از خواندنهای یکباره بهطور نامحدود به cgroup فرایند شارژ میشوند و صدها مگابایت RAM فیزیکی را مصرف میکنند. - حفظ پشته ناشناس پساز انفجار: سرویسهایی که افزایش ناگهانی فعالیت گذرا را تجربه میکنند، مانند
Bluetoothانفجارهای اکتشاف صوتی و BLE،NetworkStackاعتبارسنجی TLS درگاه مهمان، یا انتقال کمککنندههای واسط کاربر به پسزمینه، میتوانند صفحات پشته ناشناس سرد را مدتها پساز تکمیل انفجار حفظ کنند.
اعمال کردن <memory-budget> اعلان کالیبرهشده (memory.high محدودیت نرم،
معمولاً ۳۰ مگابایت تا ۱۹۰ مگابایت) در برنامههای سیستم دو مزیت
اصلی دارد:
- بازیابی صفحه محلیشده و پیشکنشی: وقتی فرایند سیستم از بودجه
memory.highپیکربندیشده خود فراتر میرود، هسته Linux بازیابی صفحه را بهطور خاص به آن cgroup هدایت میکند، ابتدا صفحات سرد با پشتیبانی فایل را تخلیه میکند و صفحات ناشناس غیرفعال را بدون انتظار برای فشار حافظه دستگاه جهانی به ZRAM فشرده میکند. - حافظه دسترسی تصادفی (RAM) بیشتر برای برنامههای پیشزمینه و مخزن برنامه ذخیرهشده در حافظه نهان: محدود کردن حافظههای نهان فایل سرد در سرویسهای سیستم همیشه روشن، دهها تا صدها مگابایت حافظه دسترسی تصادفی (RAM) فیزیکی را در سراسر دستگاه بازیابی میکند، که این امر باعث کاهش لرزش میانای کاربر، کاهش فشار راهاندازی دوربین، و زنده نگه داشتن برنامههای کاربر بیشتر در حالت ذخیرهشده در حافظه نهان میشود.
پیکربندی بودجه حافظه برنامه سیستم
برنامههای سیستم از همان نحو مانیفست <memory-budget>، آبشار حالت پردازش، مقیاسبندی تراکم نمایش، و قانون وضوح عبارت آخرین تطابق که برنامههای عمومی استفاده میکنند بهره میبرند. برای فهرست کامل
مشخصهها، به مرجع مشخصه XML مراجعه کنید.
سازندگان تجهیزات اصلی میتوانند عناصر <memory-budget> را مستقیماً در AndroidManifest.xml برنامه سیستم اعلام کنند یا آنها را از فایل XML جداگانهای بااستفاده از ویژگی additional_manifests در Android.bp ادغام کنند. طبق قرارداد، 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 را در سطح cgroup شناسه کاربری (/sys/fs/cgroup/uid_<uid>/memory.high) یا در سطح cgroup شناسه فرایند (/sys/fs/cgroup/uid_<uid>/pid_<pid>/memory.high) اعمال میکند یا نه، همانطور که در شکل ۴ نشان داده شده است:
- بودجه سطح بسته (
<application>): زمانی استفاده میشود که APK یک فرایند واحد را تحت UID اختصاصی خود اجرا میکند (برای مثال،Bluetooth،Nfc،NetworkStack،CalendarProvider،Traceur، یاAppSearch). - بودجه سطح فرایند (
<processes><process>): زمانی استفاده میشود که APK با دیگر بستههای سیستم همرسانی میکندandroid:sharedUserId(مانندandroid.uid.phoneبا شناسه کاربر1001یاandroid.uid.systemبا شناسه کاربر1000) تا دیگر فرایندهایی که آن شناسه کاربر را همرسانی میکنند باهم محدود نشوند، یا زمانی که یک APK چندین فرایند را با نقشهای حافظه متمایز اجرا میکند (برای مثال، دیمن پسزمینهMediaProviderو زیرفرایند میانای کاربری:PhotoPicker).
شکل ۴. سقف حافظه سطح UID درمقابل سطح PID.
مثال زیر MediaProvider-budget.xml را نشان میدهد که بودجههای ردهبندیشده براساس RAM را به فرایند پیشفرض MediaProvider (<process>) و بودجه مقیاسبندیشده براساس نمایش را به فرایند واسط کاربر :PhotoPicker محدود میکند. هر مشخصه android:maxDeviceRamMb با دستگاههایی مطابقت دارد که کل
حافظه دسترسی تصادفی فیزیکی (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>
نحوه کالیبره شدن بودجههای مرجع AOSP در دستگاههای Google Pixel
بودجههای حافظه برنامه سیستم مرجع در AOSP در سراسر دستگاههای Google Pixel با حافظه دسترسی تصادفی فیزیکی ۶ تا ۱۶ گیگابایت (شامل تلفنها، دستگاههای تاشو، و رایانههای لوحی ۶، ۸، ۱۲، و ۱۶ گیگابایتی) و وضوح نمایشگر از حدود ۱٫۲ مگاپیکسل (۷۲۰×۱۶۰۰) تا حدود ۴٫۵ مگاپیکسل (۲۰۷۶×۲۱۵۲) کالیبره شدهاند.
کالیبره کردن دو منبع داده مکمل را ترکیب کرد: دورسنجی فیلد cgroup v2 در سراسر ناوگان و جاروبهای memory.high دستگاه فیزیکی کنترلشده در سراسر مسیرهای قطعی کاربر (CUJ).
تحلیل دورسنجی cgroup v2 در سراسر ناوگان
عکسهای آنی دورهای cgroup v2 در سراسر ناوگان دستگاه جمعآوری شد و براساس ردیف حافظه دسترسی تصادفی فیزیکی (کمتر از ۸ گیگابایت، ۱۲ گیگابایت، و بیشتر از ۱۶ گیگابایت) و دسته وضعیت فرایند (foreground، perceptible، background، و cached) تقسیم شد. شش اصل راهنمای تحلیل آماری بود:
- Decompose
memory.currentinto working set versus reclaimable file cache: Becausememory.highgoverns resident cgroup charge (memory.current), each snapshot was decomposed usingmemory.statinto anonymous heap (anon), swapped anonymous pages (swap), and file-backed page cache (file), as shown in figure 5. مجموع تقاضای ناشناس غیرقابلفشردهسازی (anon + swapدر صدک ۹۹) حداقل کف مجموعه کاری را برای بودجه تعیین میکند تا فرایند با خطر اتمام ZRAM مواجه نشود، درحالیکه فاصله زیاد بینmemory.currentصدک ۹۹ وanon + swapصدک ۹۹ نشاندهنده حافظه نهان صفحه فایل است کهmemory.highمیتواند آن را بازیابی کند، مشروط بر اینکه حافظه نهان نگاشتنشده و سرد باشد. - حساب حافظهای که
memory.highنمیتواند پس بگیرد: همه فایلها و حافظه مشترک حافظه پنهان سرد نیستند. صفحههایی که قفل شدهاند (unevictableدرmemory.stat، مانند حافظه مشترک قفلشده باmlockیا RAM مهمان قفلشده یک ماشین مجازی که فرایندهای میزبان آن به cgroup برنامه شارژ میشود) یک کف سخت زیر بودجه تعیین میکنند، و صفحههای نگاشتشده (file_mapped) اغلب بخشی از مجموعه کاری فعال هستند. پیشاز اینکه حافظه فایل را قابلبازپسگیری درنظر بگیرید،unevictable،shmem، وfile_mappedرا بررسی کنید. برای مثال، حدود ۱۰۰ مگابایت از حافظهAppSearchقفل شده است و قابلتخلیه نیست، بنابراین بودجه آن این کف را بهعلاوه مجموعه کاری میزبان فعال آن پوشش میدهد، با فضای اضافی برای رشد منطقه قفلشده. - فیلتر کردن رقیقسازی حالت بیکار: ارائهدهندگان محتوا (
CalendarProvider) و ابزارهای توسعهدهنده درخواستی (Traceur) ۷۰٪ تا ۹۹٫۹٪ از عکسهای آنی فیلد را درحالت بیکار با حدود ۱ تا ۳ مگابایت میگذرانند. محاسبه صدکهای خام در همه عکسهای آنی، تخمینهای P95 و P99 را بهشدت رقیق میکند. درعوض، صدکها و فاصلههای اطمینان در عکسهای آنی فعال رقیقنشده محاسبه شدند (با فیلتر کردن عکسهای آنیCACHEDو عکسهای آنی خط مبنای غیرفعال). - از فاصلههای اطمینان خوشهبندیشده براساس دستگاه استفاده کنید: چون یک دستگاه
درطول زمان عکسهای آنی دورهای زیادی ارائه میدهد، درنظر گرفتن عکسهای آنی بهعنوان
نمونههای مستقل، عدم قطعیت دنباله را کمتر از واقعیت نشان میدهد. همه تخمینهای مجموعه کاری P95 و P99 بااستفاده از فاصلههای اطمینان ۹۵٪ خوشهبندیشده دستگاه محافظهکارانه (بااستفاده از تعداد دستگاه متمایز
N_devبهعنوان اندازه نمونه مؤثر) ارزیابی شدند. - درنظر گرفتن فورانهای گذرا با
memory.peak: نمونهگیری دورهای میتواند فورانهای کوتاهمدت با تخصیص بالا را ازدست بدهد (مانندNetworkStackاعتبارسنجی TLS درگاه مهمان و کاوشهای همزمان ساناد، یاBluetoothمقداردهی اولیه A2DP و BLE). برای سرویسهای انفجاری، بودجهها بهاندازهای تعیین شدند که صدک ۹۰ تا ۹۵ از بالاترین حدmemory.peakهسته در طول عمر را در سطوح RAM پوشش دهند. - مطمئن شوید که سطح RAM نشاندهنده RAM است، نه نسل دستگاه: دستگاههای جدیدتر معمولاً هم RAM بیشتر و هم ویژگیهای بیشتری دارند، بنابراین مجموعه کاری که با سطح RAM رشد میکند ممکن است درواقع با ویژگیها رشد کند. قبلاز افزودن
سطح
maxDeviceRamMb، دادهها را براساس مدل دستگاه تقسیم کنید. برای مثال،com.android.phoneبه همان P99anon + swap(حدود ۸۵ تا ۹۰ مگابایت) در تلفنهای ۱۲ گیگابایتی و ۱۶ گیگابایتی از همان نسل میرسد، درحالیکه یک دستگاه تاشو قدیمیتر ۱۲ گیگابایتی از ۴۰ مگابایت استفاده میکند. بنابراین، بودجه آن از یک مقدار واحد بدون ردیف RAM استفاده میکند تا دستگاهی با RAM کمتر که ویژگیهای تلفنی جدیدتر را ارائه میدهد، با کمبود بودجه مواجه نشود.
شکل ۵. مجموعه کاری درمقابل حافظه پنهان فایل قابلبازپسگیری.
CUJ دستگاه فیزیکی و جاروبهای مقیاسبندی نمایشگر
برای اعتبارسنجی بودجههای مشتقشده از دورسنجی و کالیبره کردن بودجههای متناسب با نمایشگر (مانند :PhotoPicker) و بودجههای پسزمینه مختص وضعیت (مانند Traceur)، پاکسازیهای زنده memory.high روی دستگاههای فیزیکی با حافظه دسترسی تصادفی (RAM) ۶ تا ۱۶ گیگابایت اجرا شد:
- یافتن زانوی بدون خطای مجدد: هنگام اجرای CUJهای سرتاسری (مانند
پرتاب سریع شبکه عکس، مرور آلبوم، تند کشیدن پیشنمایش عکس و ویدیو با وضوح بالا در حالت تمامصفحه، و ضبط و ذخیره ردگیری)،
memory.highدر حین اندازهگیری شمارندههای cgroupmemory.stat(workingset_refault_anon،workingset_refault_file،pgscan، وpgsteal) وmemory.events(high) کاهش یافت. همانطور که در شکل ۶ نشان داده شده است، بودجه بهینه درست بالای زانوی بدون خطای مجدد قرار دارد. زانوِ بدون خطای مجدد آستانهای است که در آن هسته حافظه نهان فایل یکباره سرد را بازیابی میکند (pgsteal > 0) بدون اینکه باعث کوبش مجموعه کاری فعال شود (workingset_refault == 0). - اعتبارسنجی مقیاسبندی پیکسل نمایشگر در وضوحهای مختلف: آزمایش
:PhotoPickerدر چهار وضوح نمایشگر فیزیکی و شبیهسازیشده از حدود ۱٫۲ مگاپیکسل (۷۲۰×۱۶۰۰) تا حدود ۴٫۵ مگاپیکسل (نمایشگر داخلی بازشده ۲۰۷۶×۲۱۵۲) تأیید کرد که مجموعه کاری نقشه بیتی Glide و ViewPager2 فعال آن بهصورت خطی با تعداد پیکسلهای نمایشگر مقیاسبندی میشود. خط پایه غیرنمایشگر نیز براساس دستگاه متفاوت است: در تعداد پیکسل تقریباً یکسان، زانوی بدون خطای مجدد حدود ۱۴۰ مگابایت در نمایشگر بیرونی تاشو ۱۶ گیگابایتی درمقابل ۱۱۰ تا ۱۲۵ مگابایت در تلفن ۶ گیگابایتی بود. خط پایه ۸۵ مگابایتی بهعلاوه ۲۵ بایت بهازای هر پیکسل نمایشگر (android:maxMb="85"وandroid:additionalBytesPerDisplayPixel="25") در همه نمایشگرهای آزمایششده بالاتر از زانوی اندازهگیریشده باقی میماند (حدود ۱۱۰ مگابایت در HD+، حدود ۱۴۵ مگابایت در FHD+، و حدود ۱۹۰ مگابایت در نمایشگرهای بازشده). - درستیسنجی جمعآوری زباله ART در حالتهای پسزمینه: در cgroup v2،
صفحههای تصویر چارچوب و
boot.artهمرسانیشده با Zygote همچنان به cgroup مربوط به Zygote شارژ میشوند و درطول جمعآوری زباله فشردهسازی علامتگذاری همزمان (CMC) مربوط به ART بهعنوان فضای ایمن درنظر گرفته میشوند. آزمایش فشار تأیید کرد که وقتی برنامه واسط کاربر سیستم بهbackgroundمنتقل میشود، سختگیرانهتر کردنmemory.high(برای مثال، به ۳۰ مگابایت درTraceur) بهطور تمیز پشته خصوصی و حافظه نهان صفحه را بدون ایجاد کوبش GC یا فعالیت مبادله محدود میکند.
شکل ۶. یافتن زانوی صفر-پیشفرض درطول CUJ.
خلاصه بودجههای برنامه سیستم مرجع AOSP
جدول زیر بودجههای مرجع کالیبرهشده را در AOSP در سراسر سطوح RAM و حالتهای پردازش خلاصه میکند:
| بسته یا فرایند سیستم | حوزه | ≤۸ گیگابایت RAM | ۱۲ گیگابایت حافظه دسترسی تصادفی | ≥۱۶ گیگابایت حافظه دسترسی تصادفی | درایور واسنجی اصلی |
|---|---|---|---|---|---|
com.android.bluetooth |
UID (<application>) |
۸۰ مگابایت | ۹۵ مگابایت | ۱۱۰ مگابایت | Covers P90 lifetime memory.peak bursts (~75 to 110 MB) and >2x P99 active memory.current. |
com.android.nfc |
UID (<application>) |
۵۰ مگابایت | ۶۰ مگابایت | ۶۰ مگابایت | «شبیهسازی کارت میزبان» فعال P99 (تا حدود ۵۰ مگابایت) و P90 تا P95 memory.peak را هنگام هرس کردن حافظه نهان فایل سرد پوشش میدهد. |
com.android.providers.calendar |
UID (<application>) |
۷۰ مگابایت پیشفرض (پیشزمینه) ۵۰ مگابایت perceptible و background |
مجموعه کاری فعال در سطوح RAM ثابت است. بودجه پسزمینه فضای خالی ناشناسی را برای زنگهای هشدار یادآوری نگه میدارد و درعینحال حافظه پنهان صفحه SQLite را درطول همگامسازیها کوتاه میکند. | ||
com.android.traceur |
UID (<application>) |
۸۵ مگابایت پیشفرض (پیشزمینه و قابلدرک) ۳۰ مگابایت background |
درطول ضبط و صادر کردن ردگیری فعال (TraceService)، فضای آزاد ۸۵ مگابایتی را بهطور کامل حفظ میکند، درحالیکه حالت غیرفعال و همهفرستی را به ۳۰ مگابایت محدود میکند. |
||
com.android.providers.media.module (اصلی) |
شناسه محصول (<process>) |
۶۰ مگابایت | ۷۵ مگابایت | ۸۵ مگابایت | ~۱۰ تا ۳۰ مگابایت فضای خالی بیشتر از P99 anon + swap فراهم میکند و درعینحال حافظه پنهان فایل ریزعکس و SQLite سرد را بازیابی میکند. |
com.android.providers.media.module:PhotoPicker |
شناسه محصول (<process>) |
۸۵ مگابایت + ۲۵ بایت بهازای هر پیکسل (تقریباً ۱۱۰ مگابایت در HD+، تقریباً ۱۴۵ مگابایت در FHD+، تقریباً ۱۹۰ مگابایت در تاشو ۴٫۵ مگاپیکسلی) |
بهطور متناسب با تعداد پیکسلهای نمایشگر (additionalBytesPerDisplayPixel="25") مقیاسبندی میشود تا با زانوی مجموعه کاری نقشه بیتی Glide مطابقت داشته باشد. |
||
com.android.networkstack |
UID (<application>) |
۶۵ مگابایت | ۷۰ مگابایت | ۸۵ مگابایت | حافظه عمدتاً ناشناس، با اندازه طول عمر P95 memory.peak برای پوشش دادن انفجارهای DHCP، DNS، و TLS درگاه مهمان. |
com.android.appsearch.apk |
UID (<application>) |
۱۳۰ مگابایت | حدود ۱۰۰ مگابایت حافظه قفلشده و غیرقابلتخلیه بهعلاوه حدود ۵ مگابایت مجموعه کاری میزبان فعال را پوشش میدهد، با فضای اضافی برای رشد منطقه قفلشده. خطای مجدد صفر در ≥۱۲۵ مگابایت اندازهگیری شد درحالیکه حافظه نهان صفحه سرد (تا حدود ۳۳۰ مگابایت در P99) بازیابی شد. | ||
com.android.phone (TeleService) |
شناسه محصول (<process>) |
۱۲۰ مگابایت | محدوده هر PID در UID مشترک ۱۰۰۱. مجموعه کاری بهجای RAM، نسل دستگاه را ردیابی میکند، بنابراین یک بودجه واحد حدود ۳۰ مگابایت بالاتر از بالاترین P99 anon + swap برای هر مدل قرار میگیرد. |
||
چگونه سازندگان اصلی تجهیزات میتوانند بودجههای برنامه سیستم را برای دستگاههای خودشان واسنجی کنند
تولیدکنندگان تجهیزات اصلی که برنامههای سیستم را سفارشیسازی میکنند (برای مثال، افزودن نمایههای بلوتوث فروشنده،
افزونههای تلفنی سفارشی، یا نمایهسازهای رسانه تولیدکننده تجهیزات اصلی) یا سرویسهای سیستم پیشنصبشده اضافی
ارائه میدهند میتوانند بودجههای موجود را مجدداً کالیبره کنند یا فایلهای *-budget.xml جدیدی
برای مجموعه سختافزار خود ایجاد کنند.
جمعآوری نمایههای حافظه cgroup v2 فعال
برای هر فرایند سیستم هدف، گرههای حافظه cgroup v2 آن را در
/sys/fs/cgroup/uid_<uid>/pid_<pid>/ در سراسر حجمهای کاری نماینده و سطوح
RAM بخوانید:
-
memory.current: حافظه مقیم فعلی که به cgroup شارژ شده است (بهاستثنای صفحههای مشترک Zygote) -
memory.peak: بالاترین حدmemory.currentدر طول عمر از زمان شروع فرایند -
memory.swap.current: میزان استفاده فعلی از فضای مبادله فشردهشده در ZRAM -
memory.stat: تفکیکanon،file،pgscan،pgsteal،workingset_refault_anon، وworkingset_refault_file memory.events: تعداد تجمعی نقضهایhigh(memory.highرویدادهای محدودسازی و بازپسگیری)
هنگام جمعآوری دورسنجی از دستگاههای آزمایشی یا میدانی، حالتهای فرایند فعال جداگانه (TOP، FOREGROUND_SERVICE، اتصالهای فعال، و همگامسازیهای فعال) از حالتهای غیرفعال CACHED یا غیرفعال PERSISTENT بهگونهای که عکسهای آنی غیرفعال محاسبات مجموعه کاری P95 و P99 شما را بهسمت پایین منحرف نکنند.
جدا کردن توده غیرقابلفشردهسازی از حافظه نهان فایل قابلبازپسگیری
مقایسه صدک نودونهم anon + swap با صدک نودونهم
memory.current:
- سرویسهای تحت سلطه حافظه نهان فایل (
file≫anon، مانند ارائهدهندگان پایگاه داده، نمایهسازهای جستجو، و دیمونهای گزارش):android:maxMbرا تنظیم کنید تا فضای راحتی (معمولاً ۱٫۵ تا ۴ برابر) نسبتبه 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 استفاده کنید (یا
مستقیماً در گره cgroup فرایند 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> 60MBmemory.stat و memory.events را قبل و بعداز CUJ پایش کنید:
- بودجه خیلی کم است:
workingset_refault_anonیاworkingset_refault_fileدرطول CUJ بهشدت افزایش مییابد،memory.swap.currentبهطور مداوم درطول کار فعال پیشزمینه رشد میکند، یا تأخیر Binder یا قاب CUJ پسرفت میکند. بودجه را از زانوی پیشفرض بیشتر کنید. - بودجه خیلی زیاد است:
memory.events:highحتی پساز حجم کاری سنگین نمایهسازی یا جاریسازی فایل،0باقی میماند وfileدرmemory.statبا صفحات سرد بهطور نامحدود رشد میکند. بودجه را برای مجموعه کاری فعال محدود کنید. - بودجه بهخوبی کالیبره شده است:
memory.currentحالت پایدار درطول عملکرد عادی زیرmemory.highمیماند. درطول انفجارهای سنگین فایل یا حافظه پنهان،pgstealصفحات فایل سرد را بازیابی میکند درحالیکهworkingset_refault_anonنزدیک به صفر باقی میماند و تأخیر CUJ بدون تغییر میماند.