שימוש בזיכרון של מפת הסיביות (bitmap)

מפות סיביות הן לרוב האובייקטים הכי גדולים שצורכים זיכרון באפליקציה. פעולות של פענוח ושינוי גודל נמצאות לעיתים קרובות בנתיב הקריטי של עיבוד מסגרות. אופטימיזציה של השימוש בזיכרון של מפת הסיביות (bitmap) משפרת באופן משמעותי את מהירות התגובה של ממשק המשתמש, את חיי הסוללה ואת היציבות הכוללת, על ידי צמצום בעיות בממשק (jank), שגיאות ANR וסגירת תהליכים שקשורים לשגיאות OOM.

זיהוי שימוש גבוה בזיכרון של מפת הסיביות (bitmap)

בתפקוד האפליקציה מוצגים מדדים לגבי טביעת הרגל של זיכרון מפת הסיביות של האפליקציה, על ידי צבירת נתונים ממכשירי Android. המדדים האלה כוללים אחוזונים לפי חבילה ותהליך שמבוססים על תקופה (למשל, 28 ימים). הנתונים האלה עוזרים לזהות מגמות ונסיגות פוטנציאליות ביעילות הזיכרון בסוגים ובגרסאות שונים של מכשירים.

במדד תפקוד האפליקציה ל-Android מוצג השימוש בזיכרון של מפת הסיביות (bitmap) באפליקציה, לפי מצבי התהליך הבאים:

  • חזית: התהליך של האפליקציה גלוי. הערך של P99 צפוי להיות גבוה משמעותית בפורגראונד לעומת מצבי תהליך אחרים, אבל מפתחים צריכים לבדוק אם היחס בין P99 ל-P50 משמעותי (למשל, גבוה מפי 3.5), כי לרוב זה מצביע על דליפת זיכרון של מפת סיביות. אפשר לזהות את הבעיה הזו על ידי השוואה בין השימוש הרגיל (אחוזון 50) לבין השימוש החריג (אחוזון 99). בעוד שנפיחות כללית של נכסים מגדילה את הזיכרון באופן אחיד בכל האחוזונים, דליפות זיכרון מצטברות לאורך זמן, וגורמות להטיה חזקה בנתונים של הקצה העליון (אחוזון 99). מוודאים שהקצאות של מפת סיביות בחזית לא נשמרות שלא לצורך אחרי שהאפליקציה עוברת למצבים אחרים.
  • שירותים שהשפיעו על המשתמשים: התהליך של האפליקציה פועל במצב מורגש. ההגבלה כוללת שירותים שפועלים ברקע, משימות מואצות ומשימות של העברת נתונים ביוזמת המשתמשים. אסור לאפליקציות לשמור הקצאות של מפות סיביות כבדות ברקע כשעוברים למצבים האלה. השירותים האלה מיועדים למשימות שרצות לאורך זמן, ולכן שמירה של נכסים גדולים פוגעת בחוויית המשתמש הכוללת ומאלצת את Low Memory Killer Daemon ‏(LMKD) לפנות זיכרון על ידי סגירה של תהליכים עם עדיפות נמוכה יותר.
  • רקע: האפליקציה מפעילה שירות הפועל ברקע, או שהועברה לאחרונה לרקע, אבל עדיין לא נשמרה במטמון. מצב התהליך הזה פחות חשוב מתהליכים שפועלים בחזית או תהליכים מורגשים, ולכן אפליקציות צריכות לשחרר כאן באופן מפורש נכסי מפת סיביות גדולים כדי להפחית את העומס על הזיכרון.
  • במטמון: האפליקציה נמצאת במצב מטמון. המצב הזה רגיש מאוד לעומס על זיכרון המערכת, כמו LMK. כדי למנוע את הסרת האפליקציה על ידי מערכת ההפעלה, האפליקציות צריכות לצמצם באופן יזום את השימוש בזיכרון של מפת הסיביות במצב הזה.

גורמים לשימוש גבוה בזיכרון של מפת הסיביות

יכול להיות שגם זיכרון וירטואלי שלא נעשה בו שימוש ייכלל בחישוב. אם אתם רואים שימוש גבוה באופן לא צפוי בזיכרון של מפת הסיביות (bitmap), ודאו שאתם לא מקצים זיכרון שלא נעשה בו שימוש.

משאבים

ניתוח מפות ביט ב-Android Studio

פרופיל של מפות סיביות ב-Android Studio

אפשר להשתמש בכלי Memory Profiler כדי לבדוק הקצאות זיכרון בזמן אמת, ללכוד תמונות מצב של ה-heap ולנתח אובייקטים כדי לזהות דליפות זיכרון. בנוסף, אפשר להשתמש בכלי Heap Analyzer כדי לזהות דליפות זיכרון, לזהות הקצאות כפולות של מפות סיביות ולהציג חזותית את השמירה של אובייקטים.

זיהוי אוטומטי של דליפות זיכרון באמצעות LeakCanary

כדאי לשלב את ספריית LeakCanary כדי לאוטומט את הזיהוי של דליפות זיכרון באפליקציה. LeakCanary מספקת ניתוח אוטומטי של ה-heap, ומזהה אובייקטים שהיו אמורים לעבור איסוף זבל אבל עדיין נשמרים בזיכרון, כמו מפות סיביות שנשמרו על ידי פעילויות או רכיבים שהושמדו.

מסמכי תיעוד בנושא ביצועים של מפת סיביות (bitmap)

במקורות המידע האלה מפורטות שיטות מומלצות לטיפול יעיל במפות סיביות ברכיבים שונים של Android.

רשימת משימות למפתחים לביצוע אופטימיזציה של השימוש בזיכרון של מפת הסיביות (bitmap)

כדי לבצע אופטימיזציה של יעילות הזיכרון של מפת סיביות (bitmap), צריך לפעול לפי שלושת העקרונות המרכזיים: צמצום, שימוש חוזר ומיחזור.

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

רשימת המשימות הבאה למפתחים יכולה לעזור לכם לבצע אופטימיזציה של השימוש בזיכרון של מפת סיביות.

עקרון מרכזי אזור תיאור
הפחתה הסרת מפות סיביות כפולות כדי לזהות הקצאות מיותרות של מפות סיביות, אפשר לנתח תמונות מצב של הזיכרון באמצעות הכלי Memory Profiler. אפשר לעיין במדריך בנושא ניהול זיכרון של מפת סיביות.
שימוש בספריות לטעינת תמונות מומלץ להשתמש בספריות כמו Glide ו-Coil כדי להפוך את יצירת השרשורים, השמירה במטמון והפענוח היעיל לאוטומטיים.
הטמעה של דגימה מצומצמת פענוח תמונות כדי להתאים למידות של מאגר רכיבי ממשק המשתמש במקום לטעון נכסים ברזולוציה מלאה.
שימוש ב-RGB_565 לתמונות אטומות אפשר להקטין את הזיכרון שבשימוש ב-50% על ידי מעבר מ-ARGB_8888 להגדרה של 16 ביט לתמונות ללא שקיפות.
עדיפות ל-VectorDrawables מומלץ להשתמש בוקטורים לסמלים ולגרפיקה בסיסית כדי להבטיח שינוי גודל חד עם תקורה מינימלית של זיכרון.
אופטימיזציה של שליחת תמונות מצד השרת הגדרת ממשקי API של קצה עורפי כדי להציג תמונות שמותאמות לדחיסות המכשיר ולמידות של ImageView.
הסרת שוליים שקופים כדי להימנע מהקצאת זיכרון לפיקסלים 'בלתי נראים', כדאי להשתמש ב-InsetDrawable או במרווחים פנימיים של פריסת רכיבים במקום במרווחים קבועים. מידע נוסף זמין במאמר פיתוח אפליקציות ל-Android עם ביצועים טובים של זיכרון.
שימוש חוזר הגדרת גדלי מטמון אופטימליים התאמה של מגבלות הזיכרון והמטמון בדיסק בהתאם לזיכרון ה-RAM ולרזולוציית המסך של המכשיר. אפשר להיעזר במאמר בנושא שמירה במטמון של מפות סיביות.
מיחזור מחיקת משאבים ברקע הטמעה של TRIM_MEMORY_BACKGROUND כדי לנקות מטמונים ולשפר את היכולת של התהליך לשרוד במהלך לחץ על זיכרון המערכת.
הסרת נכסים כשהממשק מוסתר משתמשים ב-TRIM_MEMORY_UI_HIDDEN כדי לשחרר מטמונים של מפות סיביות כשהאפליקציה לא גלויה יותר למשתמש.
מעקב אחרי דליפות זיכרון אפשר להשתמש ב-LeakCanary וב-Memory Profiler כדי למצוא מפות סיביות שנשמרו אחרי שהרכיב LifecycleOwner נהרס. מידע נוסף מפורט במאמר בנושא ניהול הזיכרון של האפליקציה.