ניהול יעיל של הזיכרון במשחקים

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

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

תגובה ל-onTrimMemory()

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

אם השבתת את האפליקציה ברקע, אז בפעם הבאה שהמשתמש יופעל הם יחוו איטיות הפעלה במצב התחלתי (cold start). אפליקציות שמפחיתות לשימוש בזיכרון כשעוברים לרקע, רקע.

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

Kotlin

class MainActivity : AppCompatActivity(), ComponentCallbacks2 {
    override fun onTrimMemory(level: Int) {
        if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
            // Release memory related to UI elements, such as bitmap caches.
        }
        if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
            // Release memory related to background processing, such as by
            // closing a database connection.
        }
    }
}

Java

public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 {
    public void onTrimMemory(int level) {
        switch (level) {
            if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
                // Release memory related to UI elements, such as bitmap caches.
            }
            if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
                // Release memory related to background processing, such as by
                // closing a database connection.
            }
        }
    }
}

C#‎

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

class LowMemoryTrigger : MonoBehaviour
{
    private void Start()
    {
        Application.lowMemory += OnLowMemory;
    }
    private void OnLowMemory()
    {
        // Respond to low memory condition (e.g., Resources.UnloadUnusedAssets())
    }
}

שימוש בגרסת הבטא של Memory Advice API

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

כדי להשתמש ב-Memory Advantage API צריך להשתמש המדריך לתחילת העבודה.

מקפידים על יכולות שמרניות של תקציבי זיכרון

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

  • גודל ה-RAM הפיזי: לעיתים קרובות, במשחקים נעשה שימוש ב-1⁄4 מ-1⁄2 מהזיכרון הפיזי. כמות ה-RAM במכשיר.
  • גודל zRAM מקסימלי: אם נפח האחסון גדול יותר, יכול להיות שלמשחק יהיה יותר זיכרון להקצות. הסכום הזה יכול להשתנות בהתאם למכשיר. צריך לחפש את SwapTotal ב- /proc/meminfo כדי למצוא את הערך הזה.
  • שימוש בזיכרון של מערכת ההפעלה: במכשירים שמקצים יותר זיכרון RAM לתהליכי המערכת, נשאר פחות זיכרון למשחק. המערכת משביתה את המשחק לפני שהוא הורג תהליכים במערכת.
  • שימוש בזיכרון של אפליקציות מותקנות: בדיקת המשחק במכשירים שבהם יש הרבה האפליקציות שהותקנו. אפליקציות של רשתות חברתיות וצ'אט צריכות לפעול כל הזמן, והן משפיעות על נפח הזיכרון הפנוי.

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

הימנעות מטרחה מיותרת

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

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

שימוש בכלים הזמינים

ל-Android יש אוסף כלים שיעזרו לכם להבין איך המערכת מנהלת את הזיכרון.

Meminfo

הכלי הזה אוסף נתוני זיכרון כדי להראות כמה זיכרון PSS שהוקצתה לו והקטגוריות שבהן הוא היה בשימוש.

להדפיס את הנתונים הסטטיסטיים של meminfo באחד מ- בדרכים הבאות:

  • משתמשים בפקודה adb shell dumpsys meminfo package-name.
  • שימוש בקריאה ל-MemoryInfo מ-Android Debug API.

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

נקודות מעקב של זיכרון

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

פרפטו ועקבות ארוכים

Perfetto היא חבילה של כלים לאיסוף מידע על הביצועים והזיכרון במכשיר ולהצגה בממשק משתמש מבוסס-אינטרנט. הוא תומך במעקבים ארוכים באופן שרירותי, כדי שתוכלו לראות איך ה-RSS משתנה לאורך זמן. תוכלו גם ליצור שאילתות SQL על הנתונים שהוא מפיק לעיבוד אופליין. הפעלת מעקבים ארוכים אפליקציית System Tracing. צריך לוודא הקטגוריה memory:Memory מופעלת למעקב.

heapprofd

heapprofd הוא כלי למעקב אחרי זיכרון זה חלק מ-Perfetto. הכלי הזה יכול לעזור לך לאתר דליפות זיכרון על ידי הצגת שבו הזיכרון הוקצה באמצעות malloc. אפשר להתחיל להשתמש ב-heapprofd ב-Python, ומאחר שלכלי יש תקורה נמוכה, הוא לא משפיע ביצועים כמו כלים אחרים כמו Malloc Debug.

דוח על באג

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

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