اندروید ۱۷ و بالاتر شامل محدودکننده حافظه است، یک سرویس سیستمی که با استفاده از لینوکس cgroup نسخه ۲، میزان استفاده از حافظه توسط فرآیندهای برنامه را نظارت و محدود میکند. محدودکننده حافظه مانع از مصرف نامتناسب حافظه سیستم توسط برنامههای جداگانه میشود، که فشار کلی بر حافظه را کاهش میدهد و از حذف تهاجمی فرآیندهای حیاتی پیشزمینه و حافظه پنهان در اثر کمبود حافظه جلوگیری میکند.
مکانیسم
محدودکننده حافظه با سرویس مدیریت فعالیت (AMS) ادغام میشود تا رویدادهای چرخه حیات فرآیند و تغییرات وضعیت را ردیابی کند. محدودکننده حافظه با استفاده از سلسله مراتب cgroup v2 هسته لینوکس، محدودیتهای حافظه را اعمال میکند.
برای پشتیبانی از محدودکننده حافظه، هسته دستگاه باید cgroup v2 و کنترلکننده memory را فعال کند. این سرویس به طور خاص به ویژگیهای زیر متکی است:
-
memory.high - یک حد نرم. وقتی از آن تجاوز شود، فرآیند متوقف میشود و هسته تلاش میکند تا صفحه را از آن فرآیند به صورت پیشگیرانه بازپس بگیرد.
-
memory.swap.max - حداکثر مقدار فضای swap (مانند ZRAM) که فرآیند میتواند استفاده کند را محدود میکند.
تأثیر بر برنامهها
برنامههایی که در محدوده حافظه خود کار میکنند، تحت تأثیر محدودکننده حافظه قرار نمیگیرند.
وقتی یک برنامه از حد مجاز memory.high خود عبور میکند، هسته حافظهی فایل پشتیبان پاک برنامه را خارج میکند و حافظهی ناشناس غیرفعال آن را مبادله میکند تا برنامه در محدودهی مجاز باقی بماند. در نتیجهی این فعالیتِ خروج صفحه و مبادله، برنامه ممکن است به طور موقت با کاهش سرعت اجرا مواجه شود، اما همچنان به اجرا ادامه میدهد.
در شرایط حاد - مانند نشت حافظه کنترل نشده که در آن برنامه پس از اتمام فضای swap به تخصیص حافظه ناشناس ادامه میدهد - برنامه در تخصیص حافظه ناموفق بوده و خاتمه مییابد.
نظارت بر فرآیند
محدودکننده حافظه به طور پیشفرض فرآیندهای برنامه (UID >= 10000) را رصد میکند. فرآیندهای اصلی سیستم برای حفظ پایداری ضروری سیستم از این امر مستثنی هستند.
محدودکننده حافظه، محدودیتهای حافظه را بر اساس وضعیت مشاهدهپذیری فرآیند تعیین میکند:
فرآیندهای قابل مشاهده: فرآیندهایی که میزبان یک رابط کاربری قابل مشاهده توسط کاربر هستند (مانند فعالیت متمرکز فعلی یا یک تعامل فعال). از آنجا که نمایش یک رابط کاربری به مجموعه کاری بزرگتری برای رندر و خطوط لوله گرافیکی نیاز دارد، فرآیندهای قابل مشاهده محدودیت حافظه بیشتری دریافت میکنند.
فرآیندهای نامرئی: فرآیندهایی که در پسزمینه و بدون ارائه رابط کاربری (مانند سرویسهای پسزمینه یا گیرندههای پخش) کار میکنند. از آنجا که آنها اجزای رابط کاربری را رندر نمیکنند، تحت محدودیت بیشتری عمل میکنند.
جدول زیر حالتهای خاص فرآیند را به طبقهبندیهای محدودیت حافظه نگاشت میکند:
| وضعیت فرآیند | محدودیت حافظه |
|---|---|
PERSISTENT | نامحدود |
PERSISTENT_UI | نامحدود |
TOP | قابل مشاهده |
BOUND_TOP | قابل مشاهده |
FOREGROUND_SERVICE | قابل مشاهده نیست |
BOUND_FOREGROUND_SERVICE | قابل مشاهده نیست |
IMPORTANT_FOREGROUND | قابل مشاهده |
IMPORTANT_BACKGROUND | قابل مشاهده نیست |
TRANSIENT_BACKGROUND | قابل مشاهده نیست |
BACKUP | قابل مشاهده نیست |
SERVICE | قابل مشاهده نیست |
RECEIVER | قابل مشاهده نیست |
TOP_SLEEPING | قابل مشاهده |
HEAVY_WEIGHT | قابل مشاهده نیست |
HOME | قابل مشاهده نیست |
LAST_ACTIVITY | قابل مشاهده نیست |
CACHED_ACTIVITY | ذخیره شده |
CACHED_ACTIVITY_CLIENT | ذخیره شده |
CACHED_RECENT | ذخیره شده |
CACHED_EMPTY | ذخیره شده |
در حالت ذخیره شده در حافظه پنهان، فرآیندها منجمد شده و سپس تا حد امکان بازیابی میشوند.
وقتی یک فرآیند از حد مجاز memory.high تعیینشده برای خود فراتر میرود، Memory Limiter این رویداد را تشخیص میدهد و میتواند اقدامات تشخیصی مانند ثبت یک پروفایل حافظه یا ثبت یک ناهنجاری در statsd را آغاز کند.
پیکربندی
محدودکننده حافظه، پیکربندی خود را از پارتیشن vendor میخواند:
- مسیر فایل:
/vendor/etc/memory-limiter-config.xml
فرمت XML
فایل پیکربندی از طرح تعریف شده در memory-limiter-config.xsd پیروی میکند. این فایل چندین مجموعه محدودیت را بر اساس حافظه موجود تعریف میکند؛ سرویس بالاترین مجموعه محدودیت منطبق را بر اساس RAM موجود دستگاه انتخاب میکند. تمام مقادیر حافظه بر حسب مگابایت (MiB) مشخص میشوند.
<MemoryLimiterConfig>
<version>1</version>
<configList>
<!-- RAM minimums account for MemTotal excluding carve-outs. -->
<limitSet>
<!-- Limits for 16GB RAM device (MemTotal >= 15GiB): 10G/5G/5G/5G -->
<minimumRequiredMemTotal>15360</minimumRequiredMemTotal>
<memVisible>10240</memVisible>
<memNotVisible>5120</memNotVisible>
<swapVisible>5120</swapVisible>
<swapNotVisible>5120</swapNotVisible>
</limitSet>
<limitSet>
<!-- Limits for 12GB RAM device (MemTotal >= 11GiB): 8G/4G/4G/4G -->
<minimumRequiredMemTotal>11264</minimumRequiredMemTotal>
<memVisible>8192</memVisible>
<memNotVisible>4096</memNotVisible>
<swapVisible>4096</swapVisible>
<swapNotVisible>4096</swapNotVisible>
</limitSet>
<limitSet>
<!-- Limits for 8GB RAM device (MemTotal >= 7GiB): 5G/3G/3G/3G -->
<minimumRequiredMemTotal>7168</minimumRequiredMemTotal>
<memVisible>5120</memVisible>
<memNotVisible>3072</memNotVisible>
<swapVisible>3072</swapVisible>
<swapNotVisible>3072</swapNotVisible>
</limitSet>
<limitSet>
<!-- Limits for 6GB RAM device (MemTotal >= 5GiB): 4G/2G/2G/2G -->
<minimumRequiredMemTotal>5120</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سیستم (به مگابایت) مورد نیاز برای اعمال این محدودیت. سرویس این مقدار را با کل حافظه موجود گزارش شده توسط هسته در/proc/meminfoمقایسه میکند.درک میزان فضای خالی حافظه: مقدار
MemTotalهسته، DRAM فیزیکی قابل دسترس برای سیستم عامل را پس از کسر فضای خالی حافظه سختافزار و میانافزار نشان میدهد. فضای خالی، رم را برای اجزای سختافزاری تخصصی مانند پردازنده گرافیکی (GPU)، مودم باند پایه، ISP دوربین، محیطهای اجرای امن و هایپروایزرها ذخیره میکند که معمولاً بین ۵۰۰ مگابایت تا بیش از ۱ گیگابایت حافظه فیزیکی مصرف میکنند.از آنجا که
MemTotalکمتر از DRAM فیزیکی تبلیغشدهی دستگاه است، آستانههایminimumRequiredMemTotalشامل حاشیهای برای این حاشیهها میشوند. برای مثال، پیکربندی که دستگاههای ۱۶ گیگابایتی را هدف قرار میدهد،minimumRequiredMemTotalرا15360(۱۵ گیگابایت) به جای16384(۱۶ گیگابایت) تعیین میکند و یک ردیف برای دستگاههای ۱۲ گیگابایتی11264(۱۱ گیگابایت) را مشخص میکند. این تضمین میکند که هر دستگاه صرف نظر از تغییرات حاشیه در سطح برد، با ردیف مورد نظر خود مطابقت دارد.-
memVisible محدودیت حافظه موقت (
memory.high) بر حسب مگابایت که برای فرآیندهای قابل مشاهده اعمال میشود.-
memNotVisible محدودیت حافظه موقت (
memory.high) بر حسب مگابایت برای فرآیندهای غیرقابل مشاهده اعمال میشود.-
swapVisible محدودیت فضای swap (
memory.swap.max) بر حسب مگابایت که برای فرآیندهای قابل مشاهده اعمال میشود.-
swapNotVisible محدودیت فضای swap (
memory.swap.max) بر حسب مگابایت برای فرآیندهای غیرقابل مشاهده اعمال میشود.
محدودیتهای استاندارد پلتفرم
در اندروید ۱۷ و بالاتر، پلتفرم محدودیتهای استاندارد حافظه و فضای ذخیرهسازی را در /vendor/etc/memory-limiter-config.xml در بین لایههای رم فیزیکی رایج مشخص میکند:
| رم فیزیکی | حداقل مورد نیاز مم توتال (حداقل مقدار مورد نیاز) | محدودیت حافظه قابل مشاهده (memVisible) | محدودیت حافظه قابل مشاهده نیست (memNotVisible) | محدودیت سوآپ قابل مشاهده (قابل تعویض) | محدودیت سوآپ قابل مشاهده نیست (swapNotVisible) |
|---|---|---|---|---|---|
| ۱۶ گیگابایت | ۱۵,۳۶۰ مگابایت (۱۵ گیگابایت) | ۱۰،۲۴۰ مگابایت (۱۰ گیگابایت) | ۵،۱۲۰ مگابایت (۵ گیگابایت) | ۵،۱۲۰ مگابایت (۵ گیگابایت) | ۵،۱۲۰ مگابایت (۵ گیگابایت) |
| ۱۲ گیگابایت | ۱۱,۲۶۴ مگابایت (۱۱ گیگابایت) | ۸,۱۹۲ مگابایت (۸ گیگابایت) | ۴،۰۹۶ مگابایت (۴ گیگابایت) | ۴،۰۹۶ مگابایت (۴ گیگابایت) | ۴،۰۹۶ مگابایت (۴ گیگابایت) |
| ۸ گیگابایت | ۷,۱۶۸ مگابایت (۷ گیگابایت) | ۵،۱۲۰ مگابایت (۵ گیگابایت) | ۳،۰۷۲ مگابایت (۳ گیگابایت) | ۳،۰۷۲ مگابایت (۳ گیگابایت) | ۳،۰۷۲ مگابایت (۳ گیگابایت) |
| ۶ گیگابایت | ۵،۱۲۰ مگابایت (۵ گیگابایت) | ۴،۰۹۶ مگابایت (۴ گیگابایت) | ۲،۰۴۸ مگابایت (۲ گیگابایت) | ۲،۰۴۸ مگابایت (۲ گیگابایت) | ۲،۰۴۸ مگابایت (۲ گیگابایت) |
| ۴ گیگابایت | ۳،۰۷۲ مگابایت (۳ گیگابایت) | ۲،۰۴۸ مگابایت (۲ گیگابایت) | ۱,۰۲۴ مگابایت (۱ گیگابایت) | ۱,۰۲۴ مگابایت (۱ گیگابایت) | ۱,۰۲۴ مگابایت (۱ گیگابایت) |
اصول محدودیت حافظه
پیکربندی محدودکننده حافظه بر اساس اصول پلتفرم زیر طراحی شده است:
سازگاری اکوسیستم و سازگاری برنامه: محدودیتهای حافظه ثابت در بین دستگاهها، عملکرد قابل پیشبینی برنامه را در سراسر اکوسیستم اندروید تضمین میکند. برنامهها بر اساس انتظارات استاندارد حافظه توسعه داده شده و آزمایش میشوند؛ حفظ محدودیتهای یکسان پلتفرم از کاهش غیرمنتظره سرعت یا خاتمه زودهنگام جلوگیری میکند.
تخصیص منابع متناسب: محدودیتهای پلتفرم بر اساس ظرفیت رم فیزیکی کالیبره میشوند:
- فرآیندهای قابل مشاهده: تقریباً ۱/۲ تا ۲/۳ از کل رم فیزیکی را برای پشتیبانی از بارهای کاری فعال رابط کاربری، ترکیببندی و رندرینگ اختصاص داده است.
- فرآیندهای غیرقابل مشاهده: تقریباً ۱/۴ تا ۱/۳ از کل رم فیزیکی برای کارهای پسزمینه اختصاص داده شده است.
کاربرد جهانی: محدودیتها به طور یکنواخت برای تمام فرآیندهای برنامه روی دستگاه (UID >= 10000)، از جمله برنامههای سیستمی از پیش نصب شده و برنامههای OEM اعمال میشوند. محدودکننده حافظه از لیستهای مجاز برای معافیت برنامههای خاص پشتیبانی نمیکند و مدیریت عادلانه حافظه را در تمام برنامهها تضمین میکند.
عدم وجود APIهای پرسوجوی زمان اجرا: در اندروید ۱۷ و بالاتر، برنامهها نمیتوانند به صورت برنامهنویسی، محدودیتهای حافظه اختصاص داده شده به خود را در زمان اجرا پرسوجو کنند. محدودیتهای استاندارد پلتفرم با حاشیههای سخاوتمندانهای تعریف شدهاند تا برنامههای کاربردی بدون محدودیت در طول استفاده عادی کار کنند.
پویایی بازپسگیری و تعویض حافظه در هسته: هنگامی که یک فرآیند برنامه به حد بالای
memory.highخود نزدیک میشود، هسته لینوکس بازپسگیری حافظه را به طور خاص در گروه c آن فرآیند هدایت میکند. این شامل حذف صفحات غیرفعال پشتیبانگیری شده از فایل و تعویض صفحات ناشناس سرد به ZRAM میشود و سیالیت سیستم را بدون اعمال فشار حافظه سراسری حفظ میکند.
دستورات پوسته
دستور am memory-limiter به توسعهدهندگان و یکپارچهسازان سیستم اجازه میدهد تا در زمان اجرا برای توسعه، آزمایش و اشکالزدایی با سرویس تعامل داشته باشند:
am memory-limiter <SUB-COMMAND>وضعیت
زیردستور 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 - محدودیتهای مطلق محاسبهشدهی swap (
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
لغو دستی فقط برای طول عمر آن نمونه فرآیند خاص اعمال میشود. اگر فرآیند مجدداً راهاندازی شود، بر اساس وضعیت آن به محدودیتهای استاندارد باز میگردد.
لغو دستی نمیتواند از محدودیتهای فیزیکی سیستم فراتر رود.