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) שמותרת לתהליכים לא גלויים.
שינוי ההגדרות
כדי לשנות את המגבלות בכל המערכת, פועלים לפי השלבים הבאים:
- שינוי של
/vendor/etc/memory-limiter-config.xml. - כדי שהשינויים ייכנסו לתוקף, צריך להפעיל מחדש את המכשיר או את
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 UIDadb 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 1234adb shell am memory-limiter manual 1234 none // Remove the manual override for PID 1234
שינויים ידניים מברירת המחדל חלים רק על מחזור החיים של התהליך. אם התהליך מופעל מחדש, הוא חוזר למגבלות ברירת המחדל על סמך המצב שלו.