محدودکننده حافظه

اندروید ۱۷ و بالاتر از محدودکننده حافظه پشتیبانی می‌کند، که یک سرویس سیستمی است که با استفاده از لینوکس cgroup نسخه ۲، میزان استفاده از حافظه توسط فرآیندهای برنامه را نظارت و محدود می‌کند. محدودکننده حافظه مانع از مصرف بیش از حد حافظه سیستم توسط برنامه‌های خاص می‌شود، که فشار حافظه در کل سیستم را کاهش می‌دهد و از حذف تهاجمی فرآیندهای حیاتی با استفاده از پر کردن بیش از حد حافظه (OOM) جلوگیری می‌کند.

مکانیسم

محدودکننده حافظه با سرویس مدیریت فعالیت (AMS) ادغام می‌شود تا رویدادهای چرخه حیات فرآیند و تغییرات وضعیت را ردیابی کند. محدودکننده حافظه با استفاده از سیستم فایل cgroup v2 هسته لینوکس، محدودیت‌های حافظه را اعمال می‌کند.

برای استفاده از محدودکننده حافظه، هسته دستگاه باید از cgroup v2 و کنترل‌کننده memory پشتیبانی کند. این سرویس به طور خاص به ویژگی‌های زیر متکی است:

memory.high
یک محدودیت نرم. وقتی از آن عبور شود، فرآیند متوقف می‌شود و هسته تلاش می‌کند حافظه را از آن پس بگیرد.
memory.swap.max
میزان فضای swap که فرآیند می‌تواند استفاده کند را محدود می‌کند.

تأثیر بر برنامه‌ها

برنامه‌هایی که از محدودیت حافظه خود تجاوز نمی‌کنند، تحت تأثیر محدودکننده حافظه قرار نمی‌گیرند.

وقتی یک برنامه از حد مجاز 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 را آغاز کند.

پیکربندی

محدودکننده حافظه را با استفاده از یک فایل XML که در پارتیشن vendor قرار دارد، پیکربندی کنید. پیکربندی به شما امکان می‌دهد محدودیت‌های مطلق حافظه را بر اساس محدودیت‌های خاص حافظه دستگاه تنظیم کنید.

  • مسیر فایل: /vendor/etc/memory-limiter-config.xml

  • پیکربندی پیش‌فرض: اگر فایل پیکربندی پیدا نشود، یا اگر غیرقابل خواندن یا نامعتبر باشد، محدودکننده حافظه غیرفعال می‌شود.

فرمت XML

فایل پیکربندی از طرح تعریف شده در memory-limiter-config.xsd پیروی می‌کند. این فایل به شما امکان می‌دهد چندین مجموعه محدودیت تعریف کنید؛ سرویس بر اساس رم موجود دستگاه، بهترین مورد منطبق را انتخاب می‌کند. تمام مقادیر حافظه بر حسب واحد مگابایت (MiB) تعریف می‌شوند.

<MemoryLimiterConfig>
  <version>1</version>
  <configList>
    <limitSet>
      <!-- Limits for a phone with at least 14G of ram: 8G/4G/4G/4G -->
      <minimumRequiredMemTotal>14336</minimumRequiredMemTotal>
      <memVisible>8192</memVisible>
      <memNotVisible>4096</memNotVisible>
      <swapVisible>4096</swapVisible>
      <swapNotVisible>4096</swapNotVisible>
    </limitSet>
  </configList>
</MemoryLimiterConfig>
version
یک عدد صحیح مثبت که نسخه پیکربندی را مشخص می‌کند. این عدد باید ۱ باشد.
minimumRequiredMemTotal
حداقل حافظه سیستم مورد نیاز برای معتبر بودن این محدودیت تعیین شده.
memVisible
محدودیت حافظه ( memory.high ) امکان نمایش پردازش‌ها را فراهم می‌کرد.
memNotVisible
محدودیت حافظه ( memory.high ) اجازه پردازش‌های غیرقابل مشاهده را می‌داد.
swapVisible
محدودیت swap ( memory.swap.max ) اجازه پردازش‌های قابل مشاهده را می‌داد.
swapNotVisible
محدودیت swap ( memory.swap.max ) اجازه پردازش‌های غیرقابل مشاهده را می‌داد.

تغییر پیکربندی

برای تغییر محدودیت‌های سراسری سیستم، مراحل زیر را دنبال کنید:

  1. /vendor/etc/memory-limiter-config.xml ‎ را تغییر دهید.
  2. برای اعمال تغییرات، دستگاه را مجدداً راه اندازی کنید یا system_server مجدداً راه اندازی کنید.

دستورات پوسته

دستور am memory-limiter به شما و توسعه‌دهندگان اجازه می‌دهد تا در زمان اجرا برای توسعه و آزمایش با سرویس تعامل داشته باشید:

am memory-limiter <SUB-COMMAND>

وضعیت

زیردستور status وضعیت عملیاتی محدودکننده حافظه را گزارش می‌دهد:

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
محدودیت‌های حافظه مطلق محاسبه‌شده برای هر حالت را مشخص کنید.
events
تعداد دفعاتی که یک فرآیند از حد مجاز خود فراتر رفته است.
processes
تعداد فرآیندهای تحت نظارت

نادیده گرفتن

زیردستور ignore به طور موقت یک UID یا تمام فرآیندها را از محدود شدن مستثنی می‌کند. این عمل برای آزمایش عملکرد یا زمانی که به یک برنامه خاص اجازه می‌دهید از محدودیت‌هایش فراتر رود، مفید است.

adb shell am memory-limiter ignore 10087  // Ignore a specific UID
adb shell am memory-limiter ignore all    // Ignore all processes (effectively disables limiting)
adb shell am memory-limiter ignore none   // Resume normal operation

دستی

زیردستور manual ، محدودیت‌های محاسبه‌شده برای یک فرآیند خاص (توسط شناسه فرآیند یا PID) را با یک مقدار مطلق سفارشی بر حسب مگابایت (MB) لغو می‌کند:

adb shell am memory-limiter manual 1234 1024   // Set a 1024 MB limit for PID 1234
adb shell am memory-limiter manual 1234 none // Remove the manual override for PID 1234

لغو دستی فقط در چرخه حیات فرآیند اعمال می‌شود. اگر فرآیند مجدداً راه‌اندازی شود، بر اساس وضعیت آن به محدودیت‌های پیش‌فرض باز می‌گردد.