במסמך הזה אנחנו יוצאים מנקודת הנחה שביצעתם את ההנחיות לשיטות מומלצות לאפליקציות ל-Android בנושא ניהול זיכרון, כמו ניהול הזיכרון של האפליקציה.
מבוא
דליפת זיכרון היא סוג של דליפת משאבים שמתרחשת כשתוכנת מחשב לא משחררת זיכרון שהוקצה ולא נדרש יותר. דליפת זיכרון עלולה לגרום לכך שהאפליקציה תבקש ממערכת ההפעלה יותר זיכרון ממה שיש לה, וכתוצאה מכך היא תקרוס. יש כמה שיטות לא נכונות שעלולות לגרום לדליפות זיכרון באפליקציות ל-Android, למשל אי-ניפוי משאבים כראוי או אי-ביטול הרישום של מאזינים כשאין בהם יותר צורך.
במסמך הזה מפורטות כמה שיטות מומלצות שיעזרו לכם למנוע דליפות זיכרון בקוד, לזהות אותן ולפתור אותן. אם ניסיתם את השיטות שמפורטות במסמך הזה וחושדים שיש דליפת זיכרון ב-SDK שלנו, תוכלו לעיין במאמר איך מדווחים על בעיות ב-Google SDK.
לפני שפונים לתמיכה
לפני שמדווחים על דליפת זיכרון לצוות התמיכה של Google, צריך לפעול לפי השיטות המומלצות ולבצע את שלבי ניפוי הבאגים שמפורטים במסמך הזה כדי לוודא שהשגיאה לא נמצאת בקוד. יכול להיות שהשלבים האלה יפתרו את הבעיה, ואם לא, הם יספקו את המידע שדרוש לצוות התמיכה של Google כדי לעזור לך.
מניעת דליפות זיכרון
כדי להימנע מכמה מהסיבות הנפוצות ביותר לזיהום זיכרון בקוד שמשתמש ב-Google SDKs, כדאי לפעול לפי השיטות המומלצות הבאות.
שיטות מומלצות לאפליקציות ל-Android
בודקים שביצעת את כל הפעולות הבאות באפליקציה ל-Android:
- משחררים משאבים שלא בשימוש.
- להסיר את הרישום של המאזינים כשאין בהם צורך יותר.
- לבטל משימות כשאין בהן צורך.
- העברת שיטות של מחזור חיים כדי לשחרר משאבים
- שימוש בגרסאות האחרונות של ערכות ה-SDK
פרטים ספציפיים לגבי כל אחת מהשיטות האלה מופיעים בקטעים הבאים.
שחרור משאבים שלא בשימוש
כשאפליקציית Android משתמשת במשאב, חשוב לשחרר את המשאב כשלא צריך אותו יותר. אם לא תעשו זאת, המשאב ימשיך להשתמש בזיכרון גם אחרי שהאפליקציה תסיים להשתמש בו. מידע נוסף זמין במאמר מחזור החיים של פעילות במסמכי התיעוד של Android.
שחרור של הפניות לא תקינות של מפות Google ב-GeoSDKs
טעות נפוצה היא ש-GoogleMap יכול לגרום לדליפת זיכרון אם הוא מאוחסן במטמון באמצעות NavigationView או MapView. ל-GoogleMap יש יחס אחד לאחד עם NavigationView או MapView שממנו הוא מאוחזר. עליכם לוודא ש-GoogleMap לא נשמר במטמון, או שההפניה תשוחרר כשמתבצעת קריאה ל-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.
העברת שיטות של מחזור חיים כדי לשחרר משאבים
אם באפליקציה שלכם נעשה שימוש ב-Navigation SDK או ב-Maps SDK, חשוב לשחרר את המשאבים על ידי העברה של שיטות מחזור החיים (שמוצגות בכתב מודגש) אל navView
. אפשר לעשות זאת באמצעות NavigationView
ב-Navigation 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.
כדי לנפות באגים של דליפות זיכרון, פועלים לפי התהליך הבא:
- משחזרים את הבעיה. השלב הזה חיוני לניפוי הבאגים.
- בודקים אם השימוש בזיכרון צפוי. צריך לבדוק אם השימוש המוגבר שנראה כדליפה הוא למעשה הזיכרון הנדרש להפעלת האפליקציה.
- ניפוי באגים ברמה גבוהה. יש כמה כלי עזר שאפשר להשתמש בהם לניפוי באגים. יש שלוש קבוצות סטנדרטיות של כלים שיעזרו לכם לנפות באגים בבעיות שקשורות לזיכרון ב-Android: Android Studio, Perfetto ו-Android Debug Bridge (adb) – כלי שורת הפקודה.
- בודקים את השימוש בזיכרון של האפליקציה. איך מקבלים גרסת dump של אשכול ומעקב אחר הקצאות, ואז מנתחים את הנתונים.
- תיקון דליפות זיכרון.
השלבים האלה מוסברים בפירוט בקטעים הבאים.
שלב 1: משחזרים את הבעיה
אם לא הצלחתם ליצור מחדש את הבעיה, כדאי קודם לבדוק את התרחישים שיכולים להוביל לדליפת הזיכרון. אם אתם יודעים שהבעיה נוצרה מחדש, תוכלו לעבור ישירות לבדיקה של גרסת heap dump. עם זאת, אם קיבלתם רק גרסת dump של אשכול בזמן ההפעלה של האפליקציה או בנקודת זמן אקראית אחרת, יכול להיות שלא הפעלתם את התנאים להפעלת דליפת זיכרון. כדאי לנסות תרחישים שונים כשמנסים לשחזר את הבעיה:
איזו קבוצת תכונות מופעלת?
איזה רצף ספציפי של פעולות משתמש גורם לדליפה?
- ניסית להפעיל את התהליך הזה כמה פעמים?
באילו מצבים במחזור החיים האפליקציה עברה?
- ניסית כמה חזרות במצבים שונים של מחזור החיים?
מוודאים שאפשר ליצור מחדש את הבעיה בגרסה האחרונה של ערכות ה-SDK. יכול להיות שהבעיה בגרסה הקודמת כבר נפתרה.
שלב 2: בודקים אם השימוש בזיכרון של האפליקציה צפוי
כל תכונה דורשת זיכרון נוסף. כשאתם מאתרים באגים בתרחישים שונים, חשוב לבדוק אם מדובר בשימוש צפוי או אם מדובר בדליפה של זיכרון. לדוגמה, לתכונות או למשימות שונות של משתמשים, כדאי לשקול את האפשרויות הבאות:
סביר להניח שזו דליפת זיכרון: הפעלת התרחיש באמצעות מספר חזרות גורמת לעלייה בנפח השימוש בזיכרון לאורך זמן.
שימוש צפוי בזיכרון: הזיכרון מוחזר לאחר שהתרחיש נעצר.
שימוש צפוי בזיכרון: השימוש בזיכרון עולה במשך תקופה מסוימת ואז יורד. הסיבה לכך יכולה להיות מטמון מוגבל או שימוש צפוי אחר בזיכרון.
אם סביר להניח שהתנהגות האפליקציה היא שימוש צפוי בזיכרון, אפשר לטפל בבעיה על ידי ניהול הזיכרון של האפליקציה. במאמר ניהול הזיכרון של האפליקציה מוסבר איך עושים את זה.
שלב 3: ניפוי באגים ברמה גבוהה
כשמנסים לנפות באגים של דליפת זיכרון, מתחילים ברמה גבוהה ולאחר מכן מתמקדים ברמה נמוכה יותר אחרי שמצמצמים את האפשרויות. כדי לבדוק אם יש דליפת נתונים לאורך זמן, תוכלו להשתמש באחד מכלי ניפוי הבאגים ברמה גבוהה:
Android Studio Memory Profiler (מומלץ)
כלי לניתוח ביצועי הזיכרון ב-Android Studio
הכלי הזה מציג תרשים היסטוגרמה חזותי של נפח הזיכרון שנצרך. אפשר גם להפעיל יצירת גרסת dump של אשכול ומעקב אחר הקצאות מאותו ממשק. הכלי הזה הוא ההמלצה שמוגדרת כברירת מחדל. למידע נוסף, קראו את המאמר כלי לניתוחי זיכרון ב-Android Studio.
מוני הזיכרון של Perfetto
Perfetto מאפשר לכם לעקוב אחרי כמה מדדים ולשלוט באופן מדויק בנתונים, וכל זה מוצג בהיסטוגרמה אחת. למידע נוסף, ראו מספרי זיכרון של Perfetto.
כלי שורת הפקודה של Android Debug Bridge (adb)
רוב הנתונים שאפשר לעקוב אחריהם באמצעות Perfetto זמינים גם ככלי שורת פקודה adb
שאפשר לשלוח אליו שאילתות ישירות. כמה דוגמאות חשובות:
בעזרת Meminfo אפשר לראות מידע מפורט על הזיכרון בנקודת זמן מסוימת.
Procstats מספק נתונים סטטיסטיים מצטברים חשובים לאורך זמן.
נתון סטטיסטי חשוב שצריך לבדוק כאן הוא טביעת הרגל של הזיכרון הפיזי המקסימלי (maxRSS) שנדרש לאפליקציה לאורך זמן. יכול להיות שהערך של MaxPSS לא יהיה מדויק באותה מידה. כדי לשפר את הדיוק, אפשר להיעזר בדגל adb shell dumpsys procstats --help –start-testing
.
מעקב אחר הקצאות
מעקב אחר הקצאות מזהה את נתיב ה-stack שבו הוקצה הזיכרון, ואם הוא לא התפנה. השלב הזה שימושי במיוחד כשמחפשים דליפות בקוד מקורי. הכלי הזה מזהה את נתיב הסטאק, ולכן הוא יכול לשמש לניפוי באגים מהיר של שורש הבעיה או כדי להבין איך ליצור מחדש את הבעיה. במאמר ניפוי באגים בזיכרון בקוד נייטיב באמצעות מעקב אחר הקצאות מוסבר איך משתמשים במעקב אחר הקצאות.
שלב 4: בדיקת השימוש בזיכרון של האפליקציה באמצעות גרסת dump של אשכול
אחת הדרכים לזהות דליפת זיכרון היא ליצור dump של אשכול של האפליקציה ולאחר מכן לבדוק אם יש בה דליפות. dump של אשכול הוא תמונת מצב של כל האובייקטים בזיכרון של אפליקציה. אפשר להשתמש בו כדי לאבחן דליפות זיכרון ובעיות אחרות שקשורות לזיכרון.
Android Studio יכול לזהות דליפות זיכרון שלא ניתן לתקן באמצעות GC. כשאתם יוצרים גרסת dump של אשכול, Android Studio בודק אם יש פעילות או קטע שעדיין אפשר לגשת אליהם אבל כבר הושמדו.
- תיעוד תמונת מצב הזיכרון של המערכת
- ניתוח של גרסת ה-dump של אשכול כדי למצוא דליפות זיכרון
- תיקון דליפות זיכרון.
פרטים נוספים זמינים בסעיפים הבאים.
תיעוד תמונת מצב של הזיכרון
כדי לתעד dump של ערימה, אפשר להשתמש ב-Android Debug Bridge (adb) או ב-Android Studio Memory Profiler.
שימוש ב-adb כדי לצלם תמונת מצב של אשכול
כדי לצלם גרסת dump של אשכול באמצעות adb:
- מחברים את מכשיר Android למחשב.
- פותחים שורת פקודה ועוברים לספרייה שבה נמצאים הכלים של adb.
כדי לצלם גרסת dump של אשכול, מריצים את הפקודה הבאה :
adb shell am dumpheap my.app.name $PHONE_FILE_OUT
כדי לאחזר את האימג' של אשכול הזיכרון, מריצים את הפקודה הבאה:
adb pull $PHONE_FILE_OUT $LOCAL_FILE.
שימוש ב-Android Studio כדי לתעד dump של ערימה
כדי לתעד dump ערימה באמצעות Android Studio Memory Profiler, פועלים לפי השלבים שמפורטים בקטע תיעוד heapdump ב-Android.
ניתוח של תמונת המצב של הזיכרון כדי למצוא דליפות זיכרון
אחרי שתצלמו dump של ערימה, תוכלו להשתמש ב-Android Studio Memory Profiler כדי לנתח אותו. לשם כך, בצע את הצעדים הבאים:
פותחים את פרויקט Android ב-Android Studio.
בוחרים באפשרות Run (הפעלה) ואז באפשרות Debug (ניפוי באגים).
פותחים את הכרטיסייה Android Profiler.
בוחרים באפשרות זיכרון.
בוחרים באפשרות Open heap dump ובוחרים את קובץ ה-heap dump שיצרתם. בפרופילר הזיכרון מוצג תרשים של השימוש בזיכרון של האפליקציה.
משתמשים בתרשים כדי לנתח את האשפה:
לזהות אובייקטים שלא בשימוש יותר.
זיהוי אובייקטים שמנצלים הרבה זיכרון.
לראות כמה זיכרון כל אובייקט משתמש בו.
אפשר להשתמש במידע הזה כדי לצמצם או למצוא את מקור דליפת הזיכרון ולתקן אותו.
שלב 5: תיקון דליפות זיכרון
אחרי שתזהו את המקור לדליפה בזיכרון, תוכלו לתקן אותה. תיקון דליפות זיכרון באפליקציות ל-Android עוזר לשפר את הביצועים והיציבות של האפליקציות. הפרטים משתנים בהתאם לתרחיש. עם זאת, ההצעות הבאות יכולות לעזור:
חשוב לוודא שהאפליקציה מקצה ומפנה זיכרון בהתאם להמלצות במאמר בנושא Android ניהול הזיכרון של האפליקציה.
מסירים מהאפליקציה קוד או משאבים שלא בשימוש. למידע נוסף על אפליקציות ל-Android, ראו שיטות מומלצות לאפליקציות ל-Android.
כלים אחרים לניפוי באגים
אם אחרי ביצוע השלבים האלה עדיין לא מצאתם את דליפת הזיכרון ותיקנתם אותה, תוכלו לנסות את הכלים הבאים:
ניפוי באגים בזיכרון בקוד נייטיב באמצעות מעקב אחר הקצאות
גם אם אתם לא משתמשים ישירות בקוד מקורי, כמה ספריות נפוצות של Android עושות זאת, כולל ערכות ה-SDK של Google. אם אתם חושבים שדליפה בזיכרון נובעת מקוד מקורי, יש כמה כלים שאפשר להשתמש בהם כדי לנפות באגים. מעקב אחר הקצאות באמצעות Android Studio או heapprofd (תואם גם ל-Perfetto) הוא דרך מצוינת לזהות סיבות אפשריות לדליפת זיכרון, ולרוב זו הדרך המהירה ביותר לניפוי באגים.
מעקב אחר הקצאות הוא גם יתרון משמעותי, כי הוא מאפשר לכם לשתף את התוצאות בלי לכלול מידע רגיש שאפשר למצוא ב-heap.
זיהוי דליפות באמצעות LeakCanary
LeakCanary הוא כלי רב עוצמה לזיהוי דליפות זיכרון באפליקציות ל-Android. למידע נוסף על השימוש ב-LeakCanary באפליקציה, אפשר להיכנס לאתר LeakCanary.
איך מדווחים על בעיות ב-Google SDKs
אם ניסיתם את השיטות שמפורטות במסמך הזה ויש לכם חשד לדליפת זיכרון ב-SDK שלנו, פנו לתמיכת הלקוחות עם כמה שיותר מהפרטים הבאים:
השלבים לשחזור דליפת הזיכרון אם השלבים כוללים קוד מורכב, מומלץ להעתיק את הקוד שמשכפל את הבעיה לאפליקציה לדוגמה שלנו ולציין את השלבים הנוספים שצריך לבצע בממשק המשתמש כדי להפעיל את הדליפה.
קובצי dump של אשכול שנוצרו מהאפליקציה עם הבעיה שנוצרה מחדש. תיעוד של דמפים של אשכול (heap) בשני נקודות זמן שונות, שמראים שהשימוש בזיכרון גדל במידה משמעותית.
אם צפוי דליפת זיכרון מקומית, יש לשתף את הפלט של מעקב ההקצאות מ-heapprofd.
דוח על באג שנוצר אחרי שיצרתם מחדש את תנאי הדליפה.
מעקב סטאק של קריסות שקשורות לזיכרון.
הערה חשובה: בדרך כלל, נתוני מעקב סטאק לא מספיקים בעצמם לניפוי באגים של בעיות זיכרון, לכן חשוב לספק גם אחד מהפורמטים האחרים של מידע.