במערכת Android, סף מגבלת הזיכרון של Memory Limiter (Android 17 ואילך) וערך ההשוואה של נתוני תפקוד האפליקציה שקשורים לזיכרון ב-Google Play Console הוא anonymous RSS + swap. הערך הזה מייצג את רמת העומס על הזיכרון הפיזי שתהליך מסוים תופס בפועל, והוא מדד קריטי שצריך לעקוב אחריו כדי שהאפליקציה תפעל בצורה יציבה.
בשלב הזה, קשה למדוד את השימוש בזיכרון שתואם בדיוק ל-'anonymous RSS + swap' בזמן הריצה או באופן סטטי בתוך Unity Engine.
כדי לפתור את הבעיה הזו, בדף הזה מוסבר איך לעקוב אחרי הערך anonymous RSS + swap ברמת מהימנות גבוהה באמצעות קירוב בעזרת Unity Profiler, ProfileRecorder API ו-Unity Memory Profiler בסביבת Unity Engine.
בדיקת השימוש בזיכרון בזמן הריצה
ב-Unity, יכול להיות מאתגר למדוד ישירות את השימוש בזיכרון של Android בזמן ריצה, בלי תקורה, בפורמט המדויק של RSS אנונימי + החלפה. עם זאת, אפשר להעריך את הערך הזה (בטווח של 10% שונות) באמצעות ממשקי ה-API המובנים של Unity Profiler.
שיטה 1: שימוש בProfiler
כדי להעריך את השימוש הכולל בזיכרון, אפשר לסכם את הערכים שמוחזרים על ידי ממשקי ה-API הבאים של Profiler:
using UnityEngine;
using UnityEngine.Profiling;
public class MemoryMonitor : MonoBehaviour
{
public long GetEstimatedMemoryUsageBytes()
{
long totalReserved = Profiler.GetTotalReservedMemoryLong();
long monoHeapSize = Profiler.GetMonoHeapSizeLong();
return totalReserved + monoHeapSize;
}
}
שיטה 2: שימוש במחלקה ProfilerRecorder
אפשר לעקוב אחרי המדדים Total Reserved Memory ו-Gfx Reserved Memory באמצעות ProfilerRecorder:
בגרסאות פיתוח: מחשבים את הערך של 'Total Reserved Memory' (הזיכרון הכולל ששמור) פחות הערך של 'Gfx Reserved Memory' (הזיכרון ששמור ל-Gfx).
בגרסאות Release: משתמשים ישירות ב-Total Reserved Memory.
using Unity.Profiling;
using UnityEngine;
public class MemoryMonitor : MonoBehaviour
{
ProfilerRecorder totalRecorder;
#if DEVELOPMENT_BUILD
ProfilerRecorder gfxRecorder;
#endif
private void OnEnable()
{
totalRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "Total Reserved Memory");
#if DEVELOPMENT_BUILD
gfxRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "Gfx Reserved Memory");
#endif
}
private void OnDisable()
{
totalRecorder.Dispose();
#if DEVELOPMENT_BUILD
gfxRecorder.Dispose();
#endif
}
public long GetEstimatedMemoryUsageBytes()
{
#if DEVELOPMENT_BUILD
if (totalRecorder.Valid && gfxRecorder.Valid)
{
return totalRecorder.LastValue - gfxRecorder.LastValue;
}
#else
if (totalRecorder.Valid)
{
return totalRecorder.LastValue;
}
#endif
return 0;
}
}
מגבלות:
אי אפשר לעקוב אחרי הקצאות זיכרון שעוקפות את מנהל הזיכרון של Unity (למשל, NativeMalloc(IntPtr size)) באמצעות ממשקי ה-API האלה.
יכול להיות שממשקי ה-API האלה לא נתמכים, בהתאם לגרסת Unity שלכם.
ניתוח של פירוט הזיכרון (ניתוח סטטי)
אם מזוהה שימוש גבוה בזיכרון בזמן הריצה, צריך לזהות איפה הזיכרון נצרך. ניתוח של חלוקת הזיכרון מאפשר לכם לבטל הקצאות מיותרות ולצמצם את הזיכרון שבשימוש הכולל של המשחק.
Unity Memory Profiler
כדי לבצע ניתוח מעמיק של הזיכרון ולבצע אופטימיזציה של המשחק, אפשר להשתמש בחבילה Unity Memory Profiler. כדי לאתר את הפריטים שמתאימים לשימוש ב-Android OS anonymous RSS + swap:
- יצירת תמונת מצב באמצעות Unity Memory Profiler.
- פותחים את התמונה של מצב המערכת ועוברים אל All of Memory > Resident Memory on Device (כל הזיכרון > זיכרון תושב במכשיר).
חשבו את הסכום של הפריטים הבאים:
- לא נכלל במעקב
- סביבת זמן ריצה ל-Android (ART)
- פורמט מותאם
- מנוהל
איור 1. תיאורי הזיכרון מאוחסנים בזיכרון התושב
הסכום הכולל משמש כתחליף מעשי ל-anonymous RSS + swap במערכת ההפעלה Android, ומספק תובנות פרקטיות לניתוח הזיכרון של המשחק.
מגבלה:
במצבים של עומס רב על הזיכרון, מערכת ההפעלה Android עשויה לדחוס או להחליף דפי זיכרון פעילים כדי לפנות זיכרון RAM. מכיוון ש-Unity Memory Profiler לא יכול לעקוב אחרי זיכרון שהועבר, יכול להיות שיהיו אי-התאמות בתרחישים של שימוש בזיכרון גבוה.
יכול להיות שהתכונות האלה יהיו מוגבלות בהתאם לגרסת Unity שבה אתם משתמשים.
דוגמאות לסקריפטים של C#
אפשר לעיין בסקריפטים AndroidAndroidProcessStats.cs וGameMemoryMonitor.cs כדי לראות דוגמאות לאופן שבו אפשר לעקוב אחרי המצב וטביעות הזיכרון של התהליכים של המשחק בזמן הריצה.
- בסקריפט
AndroidProcessStatsמודגם איך להשתמש ב-JNI (Java Native Interface) כדי לקשר לממשקי ה-API של AndroidActivityManager, והוא מספק פונקציונליות לאחזור תהליכים שפועלים, החשיבות שלהם והמצב ברמת מערכת ההפעלה. הוא כולל גם שיטות קלות משקל לקריאת נתוני זיכרון ישירות ממערכת הקבצים של Linux/proc. - סקריפט
GameMemoryMonitorמראה איך לחבר את המידע הזה לניטור וניפוי באגים רציפים, כולל איך לבצע סקר של ממשקי ה-API של Android בשרשור ברקע כדי למנוע תקורה של ביצועים (כי שימוש ב-JNI וביצוע סקר של מידע על הזיכרון עלולים להיות יקרים), ואיך להתחבר לאירועי מחזור חיים כמוOnApplicationPauseכדי לעקוב אחרי שינויים בזיכרון כשהאפליקציה פועלת ברקע או מופעלת מחדש.
כדי להשתמש בכלים האלה, מוסיפים את שני הסקריפטים לתיקיית הנכסים ומצרפים את הסקריפט GameMemoryMonitor ל-GameObject בסצנה.
הערכה מדויקת יותר
כדי לאמת את הערכים המדויקים של מערכת ההפעלה Android anonymous RSS + swap, צריך להשתמש ב-Perfetto. הכלי מאפשר למדוד את השימוש המדויק בזיכרון ברמת המערכת ולנתח ביסודיות את הזיכרון שבשימוש של המשחק.