מגביל זיכרון

‫Android 17 ואילך תומך ב-memory limiter, שזה שירות מערכת שעוקב אחרי השימוש בזיכרון של תהליכי אפליקציות ומגביל אותו באמצעות Linux cgroup v2. התכונה Memory Limiter מונעת מאפליקציות בודדות לצרוך יותר מדי זיכרון מערכת, וכך מפחיתה את העומס על הזיכרון בכל המערכת ומונעת השבתה אגרסיבית של תהליכים קריטיים בגלל חוסר זיכרון (OOM).

מנגנון

הכלי Memory Limiter משולב עם Activity Manager Service‏ (AMS) כדי לעקוב אחרי אירועים של מחזור חיים של תהליכים ושינויים במצב. הכלי Memory Limiter אוכף מגבלות זיכרון באמצעות מערכת הקבצים cgroup v2 של ליבת Linux.

כדי להשתמש בכלי להגבלת הזיכרון, ליבת המכשיר צריכה לתמוך ב-cgroup v2 ובבקר memory. השירות מסתמך באופן ספציפי על המאפיינים הבאים:

memory.high
מגבלה רכה. אם חורגים מהמגבלה, התהליך מוגבל והליבה מנסה לשחרר ממנו זיכרון.
memory.swap.max
מגביל את כמות מרחב ההחלפה שהתהליך יכול להשתמש בו.

ההשפעה על אפליקציות

אפליקציות שלא חורגות ממגבלות הזיכרון שלהן לא מושפעות מהתכונה Memory Limiter.

כשאפליקציה חורגת מהמגבלה של memory.high, ליבת המערכת מפנה את הזיכרון של האפליקציה שגובה בקובץ ומחליפה את הזיכרון האנונימי שלה כדי שהאפליקציה תישאר במסגרת המגבלה. כתוצאה מההוצאה וההחלפה, יכול להיות שהאפליקציה תפעל לאט יותר.

במקרים קיצוניים, אם האפליקציה ממשיכה להקצות זיכרון אנונימי ובמכשיר נגמר נפח האחסון הזמני, יכול להיות שהאפליקציה לא תצליח להקצות זיכרון, וכתוצאה מכך סביר להניח שהיא תקרוס.

מעקב אחר תהליכים

כברירת מחדל, הכלי Memory Limiter עוקב אחרי תהליכים של אפליקציות (UID >= 10000). תהליכי המערכת בדרך כלל פטורים מהבדיקה כדי לאמת את היציבות של ליבת המערכת.

הכלי Memory Limiter מקצה מגבלות זיכרון על סמך מצב התהליך:

  • תהליכים גלויים הם תהליכים שהמשתמש יכול להבחין בהם, כמו פעילויות בחזית, שירותים בחזית או מצבים אחרים שבהם המשתמש יכול להבחין בבעיות.

  • תהליכים לא גלויים הם תהליכים ברקע שלא מתקיימת איתם אינטראקציה ולא ניתן לראות אותם.

בטבלה הבאה מפורט מיפוי של מצבי תהליך ספציפיים למגבלות זיכרון:

מצב התהליךמגבלת זיכרון
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.

הגדרות אישיות

מגדירים את Memory Limiter באמצעות קובץ XML שנמצא במחיצה vendor. ההגדרה מאפשרת לכם לשנות את מגבלות הזיכרון המוחלטות בהתאם למגבלות הזיכרון הספציפיות של המכשיר.

  • נתיב הקובץ: /vendor/etc/memory-limiter-config.xml

  • הגדרת ברירת מחדל: אם קובץ ההגדרות לא נמצא, או אם אי אפשר לקרוא אותו או שהוא לא תקין, מגביל הזיכרון מושבת.

פורמט XML

קובץ התצורה פועל לפי הסכימה שמוגדרת ב-memory-limiter-config.xsd. בקובץ אפשר להגדיר כמה סטים של מגבלות. השירות בוחר את ההתאמה הכי טובה על סמך ה-RAM שזמין במכשיר. כל ערכי הזיכרון מוגדרים ביחידות של מביבייט (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
מספר שלם חיובי שמזהה את גרסת ההגדרה. הערך חייב להיות 1.
minimumRequiredMemTotal
הזיכרון המינימלי שנדרש במערכת כדי שההגבלה הזו תהיה תקפה.
memVisible
מגבלת הזיכרון (memory.high) שמותרת לתהליכים גלויים.
memNotVisible
מגבלת הזיכרון (memory.high) שמותרת לתהליכים שלא גלויים.
swapVisible
מגבלת ההחלפה (memory.swap.max) שמותרת לתהליכים גלויים.
swapNotVisible
מגבלת ההחלפה (memory.swap.max) שמותרת לתהליכים לא גלויים.

שינוי ההגדרות

כדי לשנות את המגבלות בכל המערכת, פועלים לפי השלבים הבאים:

  1. שינוי של /vendor/etc/memory-limiter-config.xml.
  2. כדי שהשינויים ייכנסו לתוקף, צריך להפעיל מחדש את המכשיר או את system_server.

פקודות 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
מציינים את מגבלות הזיכרון המוחלטות המחושבות לכל מצב.
events
מספר הפעמים שתהליך חרג מהמגבלה שלו.
processes
מספר התהליכים שבמעקב.

ignore

פקודת המשנה 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

שינויים ידניים מברירת המחדל חלים רק על מחזור החיים של התהליך. אם התהליך מופעל מחדש, הוא חוזר למגבלות ברירת המחדל על סמך המצב שלו.