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

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

מבוא

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

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

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

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

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

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

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

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

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

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

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

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

שחרור הפניות לא תקינות של מפות Google ב-GeoSDKs

אחת הטעות הנפוצות היא שמפת Google יכולה לגרום לדליפת זיכרון אם היא נשמרה במטמון באמצעות 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. אם האפליקציה קורא ל-method הזה כדי להאזין לאירועי הגעה, היא צריכה גם לקרוא ל-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 ב-Navigation SDK או MapView ב-Maps SDK או ב-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) כלי שורת הפקודה (CLI).
  4. איך בודקים את השימוש בזיכרון של האפליקציה אחזור של תמונת מצב של הזיכרון אחר הקצאה, ולאחר מכן לנתח אותו.
  5. פתרון דליפות זיכרון

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

מוני זיכרון Perfetto

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

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

כלי שורת הפקודה של Android Debug Bridge‏ (adb)

הרבה הדברים שאפשר לעקוב אחריהם ב-Perfetto זמינים גם בתור adb שירות שורת פקודה שאפשר להריץ עליו שאילתה ישירות. כמה נקודות חשובות לדוגמה:

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

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

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

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

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

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

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

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

  1. צילום תמונת מצב של הזיכרון.
  2. ניתוח של תמונת מצב של הזיכרון כדי לאתר דליפות זיכרון
  3. תיקון דליפות זיכרון.

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

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

כדי לתעד תמונת מצב של הזיכרון, אפשר להשתמש ב-Android Debug Bridge (adb) או הכלי לניתוח זיכרון של Android Studio.

שימוש ב-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 ערימה באמצעות הכלי Memory Profiler ב-Android Studio, פועלים לפי השלבים שמפורטים בקטע תיעוד dump ערימה ב-Android.

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

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

  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 שלנו, פנו לתמיכת הלקוחות עם כמה שיותר מהפרטים הבאים:

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

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

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

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

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

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