שיטות מומלצות לניהול זיכרון

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

מבוא

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

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

לפני שפונים לתמיכה

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

מניעת דליפות זיכרון

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

שיטות מומלצות לאפליקציות ל-Android

בודקים שביצעת את כל הפעולות הבאות באפליקציה ל-Android:

  1. משחררים משאבים שלא בשימוש.
  2. להסיר את הרישום של המאזינים כשאין בהם צורך יותר.
  3. איך מבטלים משימות אם לא צריך
  4. העברת שיטות של מחזור חיים כדי לשחרר משאבים
  5. שימוש בגרסאות האחרונות של ערכות ה-SDK

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

שחרור משאבים שלא בשימוש

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

פרסום הפניות לא עדכניות של מפות Google בערכות GeoSDK

טעות נפוצה היא ש-GoogleMap יכול לגרום לדליפת זיכרון אם הוא מאוחסן במטמון באמצעות NavigationView או MapView. ל-GoogleMap יש יחס אחד לאחד עם NavigationView או MapView שממנו הוא מאוחזר. עליך לוודא שמפה של Google לא נשמרת במטמון או שהפניה מתפרסמת כאשר מתבצעת קריאה ל-NavigationView#onDestroy או ל-MapView#onDestroy. אם משתמשים ב-NavigationSupportFragment, ב-MapSupportFragment או בפלטפורמה משלכם שמארחת את התצוגות האלה, צריך לשחרר את ההפניה ב-Fragment#onDestroyView.

class NavFragment : SupportNavigationFragment() {

  var googleMap: GoogleMap?

  override fun onCreateView(
    inflater: LayoutInflater,
    parent: ViewGroup?,
    savedInstanceState: Bundle?,
  ): View  {
    super.onCreateView(inflater,parent,savedInstanceState)
    getMapAsync{map -> googleMap = map}
  }

  override fun onDestroyView() {
    googleMap = null
  }
}

ביטול רישום מאזינים כשאין צורך יותר

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

לדוגמה, נניח שהאפליקציה שלכם משתמשת ב-Navigation SDK והיא קוראת ל-listener הבא כדי להאזין לאירועי הגעה: השיטה addArrivalListener כדי להאזין לאירועי הגעה, היא צריכה להפעיל גם את הפקודה removeArrivalListener כשלא צריך יותר לעקוב אחרי אירועי ההגעה.

var arrivalListener: Navigator.ArrivalListener? = null

fun registerNavigationListeners() {
  arrivalListener =
    Navigator.ArrivalListener {
      ...
    }
  navigator.addArrivalListener(arrivalListener)
}

override fun onDestroy() {
  navView.onDestroy()
  if (arrivalListener != null) {
    navigator.removeArrivalListener(arrivalListener)
  }

  ...
  super.onDestroy()
}

ביטול משימות כשאין בהן צורך

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

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

העברת שיטות של מחזור חיים כדי לשחרר משאבים

אם האפליקציה שלכם משתמשת ב-SDK לניווט או למפות Google, חשוב לשחרר את המשאבים על ידי שיטות העברת מחזור החיים (שמוצגות בגופן מודגש) אל navView. אפשר לעשות זאת באמצעות NavigationView ב-SDK לניווט או MapView ב-Maps או ב-Navigation SDK. אפשר גם להשתמש ב-SupportNavigationFragment או ב-SupportMapFragment במקום להשתמש ישירות ב-NavigationView וב-MapView, בהתאמה. קטעי התמיכה מטפלים בהעברה של שיטות מחזור החיים.

class NavViewActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...
    navView = ...
    navView.onCreate(savedInstanceState)
    ...
  }

  override fun onSaveInstanceState(savedInstanceState: Bundle) {
    super.onSaveInstanceState(savedInstanceState)
    navView.onSaveInstanceState(savedInstanceState)
  }

  override fun onTrimMemory(level: Int) {
    super.onTrimMemory(level)
    navView.onTrimMemory(level)
  }

  /* Same with
    override fun onStart()
    override fun onResume()
    override fun onPause()
    override fun onConfigurationChanged(...)
    override fun onStop()
    override fun onDestroy()
  */
}

שימוש בגרסאות העדכניות ביותר של ערכות ה-SDK

ערכות ה-SDK של Google מתעדכנות כל הזמן עם תכונות חדשות, תיקוני באגים ושיפורי ביצועים. כדי לקבל את התיקונים האלה, חשוב לעדכן את ערכות ה-SDK באפליקציה.

ניפוי באגים של דליפות זיכרון

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

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

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

  1. משחזרים את הבעיה. השלב הזה חיוני לניפוי הבאגים.
  2. בודקים אם השימוש בזיכרון צפוי. בודקים שהשימוש המוגבר שנראה כדליפה הוא לא הזיכרון שנדרש להפעלת האפליקציה.
  3. ניפוי באגים ברמה גבוהה. יש כמה כלי עזר שאפשר להשתמש בהם לניפוי באגים. יש שלוש קבוצות של כלים סטנדרטיים שעוזרים לנפות באגים בבעיות זיכרון ב-Android: Android Studio, Perfetto וכלי שורת הפקודה Android Debug Bridge (adb).
  4. בדיקת השימוש בזיכרון של האפליקציה. איך מקבלים גרסת dump של אשכול ומעקב אחר הקצאות, ואז מנתחים את הנתונים.
  5. תיקון דליפות זיכרון.

הקטעים הבאים מתארים את השלבים האלה בפירוט.

שלב 1: משחזרים את הבעיה

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

  • איזו קבוצת תכונות מופעלת?

  • איזה רצף ספציפי של פעולות משתמש גורם לדליפה?

    • ניסית להפעיל את התהליך הזה כמה פעמים?
  • באילו מצבים במחזור החיים האפליקציה עברה מחזור?

    • ניסית כמה חזרות במצבים שונים של מחזור החיים?

צריך לוודא שאפשר ליצור מחדש את הבעיה בגרסה האחרונה של ערכות ה-SDK. יכול להיות שהבעיה מגרסה קודמת כבר נפתרה.

שלב 2: בודקים אם האפליקציה צפויה להשתמש בזיכרון

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

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

  • השימוש הצפוי בזיכרון: הזיכרון מוחזר אחרי הפסקת התרחיש.

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

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

שלב 3: ניפוי באגים ברמה גבוהה

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

כלי לניתוח ביצועי הזיכרון ב-Android Studio

הכלי הזה מציג היסטוגרמה ויזואלית של הזיכרון שנצרך. אפשר גם להפעיל יצירת גרסת dump של אשכול ומעקב אחר הקצאות מאותו ממשק. הכלי הזה הוא ההמלצה שמוגדרת כברירת מחדל. מידע נוסף זמין במאמר Android Studio Memory Profiler.

מוני הזיכרון של Perfetto

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

ממשק משתמש של Perfetto

כלי שורת הפקודה לניפוי באגים ב-Android (adb)

חלק גדול מהתוכן שאפשר לעקוב אחריו באמצעות Perfetto זמין גם ככלי עזר לשורת הפקודה adb, שאפשר לבצע בו שאילתות ישירות. כמה דוגמאות חשובות:

  • בעזרת Meminfo אפשר לראות מידע מפורט על הזיכרון בנקודת זמן מסוימת.

  • Procstats מספק נתונים סטטיסטיים מצטברים וחשובים לאורך זמן.

נתון סטטיסטי חיוני שיש לבדוק כאן הוא טביעת הרגל הפחמנית המקסימלית של הזיכרון הפיזית (maxRSS) שנדרשת לאפליקציה לאורך זמן. ייתכן ש-MaxPSS לא יהיה מדויק באותה מידה. למידע על דרכים לשפר את הדיוק, ראו adb shell dumpsys procstats --help –start-testing בדגל.

מעקב אחר הקצאות

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

שלב 4: בדיקת השימוש בזיכרון של האפליקציה באמצעות גרסת dump של אשכול

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

Android Studio יכול לזהות דליפות זיכרון שלא ניתן לתקן על ידי GC. כשאתם יוצרים גרסת dump של אשכול, Android Studio בודק אם יש פעילות או קטע שעדיין אפשר לגשת אליהם אבל כבר הושמדו.

  1. תיעוד תמונת מצב הזיכרון של המערכת
  2. ניתוח של גרסת ה-dump של אשכול כדי למצוא דליפות זיכרון
  3. תיקון דליפות זיכרון

פרטים נוספים מופיעים בסעיפים הבאים.

צילום של תמונת מצב של הזיכרון

כדי לתעד dump של ערימה, אפשר להשתמש ב-Android Debug Bridge‏ (adb) או ב-Android Studio Memory Profiler.

שימוש ב-adb כדי לתעד תמונת מצב של הזיכרון

כדי לתעד תמונת מצב של הזיכרון באמצעות adb:

  1. מחברים את מכשיר Android למחשב.
  2. פותחים את שורת הפקודה ועוברים לספרייה שבה נמצאים כלי ה-adb.
  3. כדי לצלם תמונת מצב של הזיכרון, מריצים את הפקודה הבאה :

    adb shell am dumpheap my.app.name $PHONE_FILE_OUT

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

    adb pull $PHONE_FILE_OUT $LOCAL_FILE.

שימוש ב-Android Studio כדי לתעד dump של ערימה

כדי לצלם תמונת מצב של הזיכרון באמצעות Android Studio Memory Profiler, פועלים לפי השלבים בקטע צילום תוכן של ערימה (heapdump) ב-Android.

ניתוח של תמונת המצב של הזיכרון כדי למצוא דליפות זיכרון

אחרי שתצלמו dump של ערימה, תוכלו להשתמש ב-Android Studio Memory Profiler כדי לנתח אותו. לשם כך, בצע את הצעדים הבאים:

  1. פותחים את פרויקט Android ב-Android Studio.

  2. בוחרים באפשרות Run (הפעלה) ולאחר מכן בוחרים בהגדרה Debug (ניפוי באגים).

  3. פותחים את הכרטיסייה Android Profiler.

  4. בוחרים באפשרות זיכרון.

  5. בוחרים באפשרות Open heap dump ובוחרים את קובץ ה-heap dump שיצרתם. בכלי לפרופיל הזיכרון מוצג תרשים של השימוש בזיכרון של האפליקציה.

  6. משתמשים בתרשים כדי לנתח את תמונת המצב של הזיכרון:

    • לזהות אובייקטים שלא בשימוש יותר.

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

    • לראות כמה זיכרון כל אובייקט משתמש בו.

  7. אפשר להשתמש במידע הזה כדי לצמצם או לאתר את מקור דליפת הזיכרון ולתקן אותה.

שלב 5: תיקון דליפות זיכרון

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

כלים אחרים לניפוי באגים

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

ניפוי באגים בזיכרון בקוד נייטיב עם מעקב הקצאה

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

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

זיהוי דליפות באמצעות LeakCanary

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

איך מדווחים על בעיות ב-Google SDKs

אם ניסיתם את השיטות שמפורטות במסמך הזה ויש לכם חשד לדליפת זיכרון ב-SDK שלנו, פנו לתמיכת הלקוחות עם כמה שיותר מהפרטים הבאים:

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

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

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

  • דוח על באג שנוצר אחרי שיצרתם מחדש את התנאי לדליפת מידע.

  • דוח קריסות של קריסות שקשורות לזיכרון.

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