במסמך הזה אנחנו מניחים שפעלתם לפי ההנחיות לשיטות מומלצות לגבי אפליקציות ל-Android בנושא ניהול זיכרון, כמו ניהול הזיכרון של האפליקציה.
מבוא
דליפת זיכרון היא סוג של דליפת משאבים שמתרחשת כשתוכנת מחשב לא משחררת זיכרון שהוקצה לה, שכבר לא נחוץ. דליפה עלולה לגרום לאפליקציה לבקש מהמערכת יותר זיכרון ממה שיש לה, וכך לגרום לקריסת האפליקציה. יש מספר שיטות לא תקינות שעלולות לגרום לדליפות זיכרון באפליקציות ל-Android, כמו אי-סילוק נכון של משאבים או אי-ביטול רישום של מאזינים כשכבר אין בהם צורך.
במסמך הזה מפורטות כמה שיטות מומלצות שיעזרו לכם למנוע דליפות זיכרון בקוד, לזהות אותן ולפתור אותן. אם ניסיתם את השיטות שמתוארות במסמך הזה ואתם חושדים שיש דליפת זיכרון בערכות ה-SDK שלנו, כדאי לעיין במאמר איך מדווחים על בעיות בערכות SDK של Google.
לפני שפונים לתמיכה
לפני שמדווחים על דליפת זיכרון לצוות התמיכה של Google, צריך לפעול לפי שיטות מומלצות ולבצע את שלבי הניפוי שמפורטים במסמך הזה כדי לוודא שהשגיאה לא נמצאת בקוד. יכול להיות שהשלבים האלה יפתרו את הבעיה, ואם לא, הם ייצרו את המידע שצוות התמיכה של Google צריך כדי לעזור לכם.
מניעת דליפות זיכרון
כדי להימנע מכמה מהגורמים הנפוצים ביותר לזליגת זיכרון בקוד שמשתמש בערכות SDK של Google, מומלץ לפעול לפי השיטות המומלצות הבאות.
שיטות מומלצות לאפליקציות ל-Android
בודקים שביצעתם את כל הפעולות הבאות באפליקציה ל-Android:
- הפצת משאבים שלא נמצאים בשימוש.
- ביטול הרישום של מאזינים כשאין בהם יותר צורך.
- ביטול משימות כשאין בהן צורך.
- העברת שיטות של מחזור חיים כדי לשחרר משאבים
- משתמשים בגרסאות העדכניות ביותר של ה-SDK.
- כדי למנוע ANR, צריך להימנע מחסימת ה-thread הראשי במהלך האתחול.
בסעיפים הבאים מפורטים פרטים ספציפיים לגבי כל אחת מהשיטות האלה.
הפצת משאבים שלא נמצאים בשימוש
כשמשתמשים במשאב באפליקציית Android, חשוב לשחרר את המשאב כשכבר לא צריך אותו. אם לא, המשאב ימשיך לתפוס זיכרון גם אחרי שהאפליקציה תסיים את השימוש בו. מידע נוסף זמין במאמר בנושא מחזור החיים של פעילות במסמכי התיעוד של Android.
שחרור הפניות לא עדכניות ל-GoogleMap ב-GeoSDKs
טעות נפוצה היא ש-GoogleMap עלול לגרום לדליפת זיכרון אם הוא נשמר במטמון באמצעות NavigationView או MapView. ל-GoogleMap יש קשר של אחד לאחד עם NavigationView או MapView שממנו הוא מאוחזר. צריך לוודא שרכיב GoogleMap לא נשמר במטמון, או שההפניה משוחררת כשמתבצעת קריאה ל-NavigationView#onDestroy או ל-MapView#onDestroy. אם משתמשים ב-NavigationSupportFragment, ב-MapSupportFragment או ב-fragment משלכם שעוטף את התצוגות האלה, צריך לשחרר את ההפניה ב-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 של Navigation או Maps, צריך לוודא שמשחררים את המשאבים על ידי העברת שיטות מחזור החיים (מוצגות בהדגשה) אל 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 באפליקציה.
כדי למנוע ANR, צריך להימנע מחסימה של ה-thread הראשי במהלך האתחול
אם אפליקציה חוסמת את השרשור הראשי למשך זמן ארוך מדי, יכולה להתרחש שגיאה מסוג ANR (האפליקציה לא מגיבה). כדי למנוע שגיאות ANR, צריך לוודא ששיטות מחזור החיים כמו onCreate() יהיו קלות ככל האפשר, על ידי דחיית משימות ארוכות או הפעלתן מחוץ לשרשור הראשי.
כדי להימנע משגיאות ANR שקשורות לאתחול של SDK:
- יוצרים רק מופע מפה אחד בכל פעם.
- מצמצמים ככל האפשר את העבודה בשרשור UI בזמן יצירת מופע של המפה.
ניפוי באגים של דליפות זיכרון
אם עדיין מופיעות דליפות זיכרון אחרי שמיישמים את כל ההצעות הרלוונטיות שמופיעות בחלקים הקודמים של המסמך הזה, צריך לבצע את התהליך הבא כדי לאתר את מקור הבעיה.
לפני שמתחילים, כדאי להבין איך מערכת Android מנהלת את הזיכרון. מידע נוסף זמין במאמר סקירה כללית על ניהול הזיכרון ב-Android.
כדי לנפות באגים של דליפות זיכרון, פועלים לפי התהליך הבא:
- משחזרים את הבעיה. השלב הזה חיוני לניפוי הבאגים.
- בודקים אם השימוש בזיכרון הוא צפוי. בודקים שהשימוש המוגבר שנראה כמו דליפה הוא לא בעצם הזיכרון שנדרש להפעלת האפליקציה.
- ניפוי באגים ברמה גבוהה. יש כמה כלי עזר שאפשר להשתמש בהם כדי לבצע ניפוי באגים. יש שלושה סטים שונים של כלים סטנדרטיים שעוזרים לנפות באגים בבעיות זיכרון ב-Android: Android Studio, Perfetto וכלי שורת הפקודה של Android Debug Bridge (adb).
- בודקים את השימוש בזיכרון של האפליקציה. קבלת תמונת מצב של הזיכרון ומעקב אחר הקצאת הזיכרון, ואז ניתוח שלהם.
- תיקון דליפות זיכרון
בקטעים הבאים מוסבר בפירוט על השלבים האלה.
שלב 1: משחזרים את הבעיה
אם לא הצלחתם לשחזר את הבעיה, כדאי קודם לשקול את התרחישים שיכולים לגרום לדליפת הזיכרון. אם יודעים שהבעיה נוצרה מחדש, אפשר לעבור ישר לבדיקת תמונת מצב של הזיכרון. עם זאת, אם מקבלים תמונת מצב של הזיכרון בהפעלת האפליקציה או בנקודה אקראית אחרת בזמן, יכול להיות שלא הפעלתם את התנאים להפעלת דליפה. כדאי לנסות לשחזר את הבעיה בתרחישים שונים:
אילו תכונות מופעלות?
מהו הרצף הספציפי של פעולות המשתמש שגורם לדליפה?
- האם ניסית להפעיל את הרצף הזה כמה פעמים?
באילו מצבים במחזור החיים האפליקציה עברה?
- ניסיתם כמה איטרציות במצבי מחזור חיים שונים?
חשוב לוודא שאפשר לשחזר את הבעיה בגרסה העדכנית של ערכות ה-SDK. יכול להיות שהבעיה מגרסה קודמת כבר תוקנה.
שלב 2: בדיקה אם השימוש בזיכרון של האפליקציה תואם לציפיות
כל תכונה דורשת זיכרון נוסף. כשמבצעים ניפוי באגים בתרחישים שונים, צריך לבדוק אם מדובר בשימוש צפוי או בדליפת זיכרון. לדוגמה, כשמדובר בתכונות שונות או במשימות משתמשים, אפשר להשתמש באפשרויות הבאות:
סביר להניח שיש דליפה: הפעלת התרחיש בכמה איטרציות גורמת לגידול בשימוש בזיכרון לאורך זמן.
השימוש הצפוי בזיכרון: הזיכרון משוחרר אחרי שהתרחיש מופסק.
שימוש בזיכרון שאולי צפוי: השימוש בזיכרון עולה למשך זמן מסוים ואז יורד. יכול להיות שהסיבה לכך היא מטמון מוגבל או שימוש צפוי אחר בזיכרון.
אם סביר להניח שהתנהגות האפליקציה היא שימוש צפוי בזיכרון, אפשר לפתור את הבעיה באמצעות ניהול הזיכרון של האפליקציה. לעזרה, אפשר לעיין במאמר בנושא ניהול הזיכרון של האפליקציה.
שלב 3: ניפוי באגים ברמה גבוהה
כשמבצעים ניפוי באגים של דליפת זיכרון, מתחילים ברמה גבוהה ואז מתמקדים אחרי שמצמצמים את האפשרויות. כדאי להשתמש באחד מכלי הניפוי באגים ברמה גבוהה כדי לנתח קודם אם יש דליפה לאורך זמן:
Android Studio Memory Profiler (מומלץ)
Android Studio Memory Profiler
הכלי הזה מציג היסטוגרמה ויזואלית של הזיכרון שנצרך. אפשר להפעיל מאותו ממשק גם תמונות מצב של הזיכרון ומעקב אחר הקצאת הזיכרון. הכלי הזה הוא ההמלצה שמוגדרת כברירת מחדל. מידע נוסף זמין במאמר בנושא Memory Profiler ב-Android Studio.
Perfetto Memory Counters
Perfetto מאפשר לכם לשלוט באופן מדויק במעקב אחרי כמה מדדים, ומציג את כולם בהיסטוגרמה אחת. מידע נוסף זמין במאמר בנושא Perfetto Memory Counters.

כלי שורת פקודה של ממשק הגישור של Android (ADB)
רוב הנתונים שאפשר לעקוב אחריהם באמצעות Perfetto זמינים גם ככלי שורת פקודה adb שאפשר להריץ עליו שאילתות ישירות. הנה כמה דוגמאות חשובות:
Meminfo מאפשר לכם לראות מידע מפורט על הזיכרון בנקודת זמן מסוימת.
Procstats מספק כמה נתונים סטטיסטיים מצטברים חשובים לאורך זמן.
נתון סטטיסטי חשוב שכדאי לבדוק כאן הוא טביעת הרגל המקסימלית של הזיכרון הפיזי (maxRSS) שהאפליקציה דורשת לאורך זמן. יכול להיות שהערך של MaxPSS לא יהיה מדויק. כדי לשפר את רמת הדיוק, אפשר להשתמש בדגל adb shell dumpsys procstats --help –start-testing.
מעקב אחר הקצאות
מעקב ההקצאות מזהה את דוח הקריסות שבו הוקצה זיכרון, ואם הזיכרון לא שוחרר. השלב הזה שימושי במיוחד כשמנסים לאתר דליפות בקוד Native. הכלי הזה מזהה את דוח קריסות, ולכן הוא יכול לעזור לכם לנפות באגים במהירות כדי לגלות את שורש הבעיה או להבין איך לשחזר אותה. הוראות לשימוש במעקב אחר הקצאת זיכרון מפורטות במאמר ניפוי באגים בזיכרון בקוד Native באמצעות מעקב אחר הקצאת זיכרון.
שלב 4: בדיקת השימוש בזיכרון של האפליקציה באמצעות תמונת מצב של הזיכרון
אחת הדרכים לזהות דליפת זיכרון היא לקבל heap dump של האפליקציה ואז לבדוק אם יש דליפות. תמונת מצב של הזיכרון היא תמונת מצב של כל האובייקטים בזיכרון של אפליקציה. אפשר להשתמש בו כדי לאבחן דליפות זיכרון ובעיות אחרות שקשורות לזיכרון.
Android Studio יכול לזהות דליפות זיכרון שלא ניתן לתקן באמצעות GC. כשמבצעים תמונת מצב של הזיכרון, Android Studio בודק אם יש Activity או מקטע (fragment) שאפשר עדיין להגיע אליהם אבל הם כבר נהרסו.
- תיעוד תמונת מצב של הזיכרון.
- ניתוח של תמונת מצב של הזיכרון כדי למצוא דליפות זיכרון.
- תיקון דליפות זיכרון.
פרטים נוספים מופיעים בסעיפים הבאים.
תיעוד תמונת מצב של הזיכרון
כדי ללכוד תמונת מצב של הזיכרון, אפשר להשתמש בממשק הגישור של Android (ADB) או בכלי Memory Profiler של Android Studio.
שימוש ב-adb כדי לצלם תמונת מצב של הזיכרון
כדי ליצור תמונת מצב של הזיכרון באמצעות adb:
- מחברים את מכשיר Android למחשב.
- פותחים שורת פקודה ועוברים לספרייה שבה נמצאים כלי ה-adb.
כדי לצלם תמונת מצב של הזיכרון, מריצים את הפקודה הבאה :
adb shell am dumpheap my.app.name $PHONE_FILE_OUTכדי לאחזר את תמונת מצב של הזיכרון, מריצים את הפקודה הבאה:
adb pull $PHONE_FILE_OUT $LOCAL_FILE.
שימוש ב-Android Studio כדי לתעד תמונת מצב של הזיכרון
כדי ללכוד תמונת מצב של הזיכרון באמצעות הכלי Memory Profiler ב-Android Studio, פועלים לפי השלבים שמפורטים בקטע Capture a heapdump במאמר בנושא Android.
ניתוח של תמונת המצב של הזיכרון כדי למצוא דליפות זיכרון
אחרי שתתעדו תמונת מצב של הזיכרון, תוכלו להשתמש בכלי Memory Profiler של Android Studio כדי לנתח אותה. לשם כך, בצע את הצעדים הבאים:
פותחים את פרויקט Android ב-Android Studio.
בוחרים באפשרות Run (הפעלה) ואז בוחרים בהגדרת Debug (ניפוי באגים).
פותחים את הכרטיסייה Android Profiler.
בוחרים באפשרות זיכרון.
בוחרים באפשרות Open heap dump (פתיחת dump של ה-heap) ובוחרים את קובץ ה-dump של ה-heap שיצרתם. בכלי ליצירת פרופיל של הזיכרון מוצג תרשים של השימוש בזיכרון של האפליקציה.
משתמשים בתרשים כדי לנתח את ה-heap dump:
לזהות אובייקטים שכבר לא בשימוש.
זיהוי אובייקטים שצורכים הרבה זיכרון.
כמה זיכרון כל אובייקט צורך.
המידע הזה יכול לעזור לכם לצמצם את האפשרויות או למצוא את המקור של דליפת הזיכרון ולתקן אותה.
שלב 5: פותרים בעיות של דליפות זיכרון
אחרי שמזהים את המקור של דליפת הזיכרון, אפשר לתקן אותה. תיקון של דליפות זיכרון באפליקציות ל-Android עוזר לשפר את הביצועים ואת היציבות של האפליקציות. הפרטים משתנים בהתאם לתרחיש. אבל ההצעות הבאות יכולות לעזור:
מוודאים שהאפליקציה מקצה זיכרון ומבטל את ההקצאה שלו בהתאם להמלצות בנושא Android ניהול הזיכרון של האפליקציה.
מסירים מהאפליקציה קוד או משאבים שלא נמצאים בשימוש. לפרטים על אפליקציות ל-Android, אפשר לעיין במאמר שיטות מומלצות לאפליקציות ל-Android.
כלים אחרים לניפוי באגים
אם אחרי השלמת השלבים האלה עדיין לא מצאתם ותיקנתם את דליפת הזיכרון, נסו להשתמש בכלים הבאים:
ניפוי באגים בזיכרון בקוד Native באמצעות מעקב אחר הקצאות
גם אם אתם לא משתמשים ישירות בקוד Native, כמה ספריות נפוצות של Android כן משתמשות בקוד Native, כולל ערכות SDK של Google. אם אתם חושבים שיש דליפת זיכרון בקוד Native, תוכלו להשתמש בכמה כלים כדי לנפות באגים. מעקב אחר הקצאה באמצעות Android Studio או heapprofd (שגם תואם ל-Perfetto) הוא דרך מצוינת לזהות גורמים פוטנציאליים לדליפת זיכרון, ולרוב זו הדרך המהירה ביותר לניפוי באגים.
יתרון נוסף של מעקב אחר הקצאות הוא האפשרות לשתף את התוצאות בלי לכלול מידע רגיש שאפשר למצוא בזיכרון.
זיהוי דליפות באמצעות LeakCanary
LeakCanary הוא כלי יעיל לזיהוי דליפות זיכרון באפליקציות ל-Android. מידע נוסף על השימוש ב-LeakCanary באפליקציה זמין בכתובת LeakCanary.
איך מדווחים על בעיות בערכות SDK של Google
אם ניסיתם את השיטות שמתוארות במסמך הזה ואתם חושדים בדליפת זיכרון בערכות ה-SDK שלנו, פנו לתמיכת הלקוחות וציינו כמה שיותר מהפרטים הבאים:
השלבים לשחזור דליפת הזיכרון. אם השלבים דורשים קידוד מורכב, כדאי להעתיק את הקוד שמשחזר את הבעיה לאפליקציה לדוגמה שלנו ולספק שלבים נוספים שצריך לבצע בממשק המשתמש כדי להפעיל את הדליפה.
קובצי Heap dump שצולמו מהאפליקציה אחרי ששחזרת את הבעיה. מבצעים צילום מצב של ה-heap בשתי נקודות זמן שונות שבהן השימוש בזיכרון גדל באופן משמעותי.
אם צפוי דליפת זיכרון מקומית, צריך לשתף את פלט המעקב אחר ההקצאה מ-heapprofd.
דוח על באג שנוצר אחרי שיצרתם מחדש את התנאי שגורם לדליפה.
עקבות מחסנית של קריסות שקשורות לזיכרון.
הערה חשובה: בדרך כלל, עקבות מחסנית לא מספיקים כדי לנפות באגים בבעיה שקשורה לזיכרון, לכן חשוב לספק גם אחד מסוגי המידע האחרים.