Gérer efficacement la mémoire dans les jeux

Sur la plate-forme Android, le système tente d'utiliser autant de mémoire système (RAM) que possible et effectue diverses optimisations de mémoire pour libérer de l'espace si nécessaire. Ces optimisations peuvent avoir un effet négatif sur votre jeu et le ralentir, voire le faire planter. Pour en savoir plus sur ces optimisations, consultez la page Allocation de mémoire entre les processus.

Cette page décrit les opérations à effectuer pour éviter que les problèmes de mémoire insuffisante n'affectent votre jeu.

Répondre à onTrimMemory()

Le système utilise onTrimMemory() pour informer votre application des événements de cycle de vie qui représentent une opportunité intéressante pour votre afin de réduire volontairement l'utilisation de sa mémoire et d'éviter d'être tuée par le le tueur de mémoire faible (LMK) afin de libérer de la mémoire pour d'autres applications.

Si votre application se ferme en arrière-plan, la prochaine fois que l'utilisateur la lancera votre application, ils connaîtront une démarrage à froid Les applications qui réduisent leur l'utilisation de la mémoire en arrière-plan sont moins susceptibles d'être supprimées en arrière-plan.

Lorsque vous répondez aux événements d'édition, il est préférable de libérer de grandes allocations de mémoire qui ne sont pas nécessaires dans l'immédiat et peuvent être reconstruits à la demande. Pour par exemple, si votre application dispose d'un cache de bitmaps qui ont été décodés à partir de stockées sous forme d'images compressées, il est recommandé de les éditer ou de les supprimer en réponse à 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())
    }
}

Utiliser la version bêta de l'API Memory Advice

L'API Memory Advice a été développée alternative à onTrimMemory, qui offre un rappel et une précision bien plus élevés à prédire les LMK imminents. Pour ce faire, l'API estime la quantité ressources de mémoire utilisées, puis en notifiant l'application lorsque certains de service sont dépassés. L'API peut également indiquer le pourcentage estimé l'utilisation de la mémoire directement à votre application. Vous pouvez utiliser l'API Memory Advice alternative à onTrimMemory à des fins de gestion de la mémoire.

Pour utiliser l'API Memory Advice, suivez le guide de démarrage.

Ne pas prendre de risque avec les budgets de mémoire

Définissez soigneusement ce budget pour éviter de manquer de mémoire. Voici quelques éléments à prendre en compte :

  • Taille de la RAM physique : les jeux utilisent souvent entre un quart et la moitié de la RAM physique sur l'appareil.
  • Taille maximale de la zRAM : plus la valeur de zRAM est élevée, plus le jeu dispose de mémoire à allouer, si nécessaire. Cette valeur peut varier en fonction de l'appareil. Recherchez SwapTotal dans /proc/meminfo pour la connaître.
  • Utilisation de la mémoire du système d'exploitation : les appareils qui réservent davantage de RAM pour les processus système en laissent moins pour votre jeu. Un tel système arrête les processus de votre jeu avant de mettre fin à ses propres processus.
  • Utilisation de la mémoire pour les applications installées : testez votre jeu sur des appareils contenant de nombreuses applications installées. Les applications de réseaux sociaux et de chat fonctionnent en permanence, ce qui réduit la quantité de mémoire disponible.

S'il vous est impossible de respecter un budget de mémoire prudent, adoptez une approche plus flexible. Si le système rencontre des problèmes de mémoire insuffisante, réduisez la quantité de mémoire utilisée par le jeu. Par exemple, allouez des textures de résolution inférieure ou stockez moins de nuanceurs en réponse à onTrimMemory(). Cette approche dynamique de l'allocation de mémoire nécessite davantage de travail de la part du développeur, en particulier lors de la phase de conception du jeu.

Éviter le thrashing

Le thrashing se produit lorsque la mémoire disponible est faible, mais pas suffisamment faible pour provoquer l'arrêt du jeu. Dans cette situation, kswapd, ayant récupéré les pages dont le jeu a encore besoin, tente de les recharger à partir de la mémoire. Mais comme l'espace est insuffisant, les pages ne cessent d'être remplacées selon un phénomène d'échange continu. Le traçage système signale cette situation sous la forme d'un thread où kswapd s'exécute en continu.

Le thrashing peut se manifester sous la forme de délais de rendu plus importants (parfois une seconde ou plus). Réduisez l'espace mémoire utilisé par le jeu pour résoudre ce problème.

Utiliser les outils disponibles

Android dispose d'un ensemble d'outils permettant de comprendre comment le système gère la mémoire.

Meminfo

Cet outil collecte des statistiques sur la mémoire pour indiquer la quantité de mémoire PSS allouée et les catégories pour lesquelles elle a été utilisée.

Affichez les statistiques meminfo de l'une des manières suivantes :

  • Exécutez la commande adb shell dumpsys meminfo package-name.
  • Utilisez l'appel MemoryInfo à partir de l'API Android Debug.

La valeur PrivateDirty indique la quantité de mémoire RAM disponible dans le processus qui ne peut pas être paginée sur le disque et qui n'est partagée avec aucun autre processus. La majeure partie de cette mémoire devient disponible pour le système lorsque ce processus est arrêté.

Tracepoints pour la mémoire

Les tracepoints pour la mémoire analysent la quantité de mémoire RSS utilisée par votre jeu. Le calcul de l'utilisation de la mémoire RSS est beaucoup plus rapide que pour la mémoire PSS. Grâce à cette rapidité, les valeurs RSS offrent une meilleure visibilité sur l'évolution de la quantité de mémoire, ce qui permet des mesures plus précises des pics d'utilisation de la mémoire. Par conséquent, il est plus facile d'identifier les moment du jeu susceptibles d'entraîner des insuffisances de mémoire.

Perfetto et les traces allongées

Perfetto est une suite d'outils permettant de collecter des informations sur les performances et la mémoire d'un appareil, puis de les afficher dans une interface utilisateur Web. Comme il prend en charge les traces allongées de longueur variable, cela vous permet de suivre l'évolution des valeurs RSS au fil du temps. Vous pouvez également effectuer des requêtes SQL sur les données qu'il produit pour analyser les valeurs hors connexion. Activez les longues traces à partir de l'application de traçage système. Assurez-vous que la catégorie memory:Memory est activée pour la trace.

Heapprofd

Le daemon heapprofd est un outil de suivi de mémoire intégré à Perfetto. Il peut vous aider à détecter les fuites de mémoire en indiquant où la mémoire a été allouée à l'aide de malloc. heapprofd peut être démarré à l'aide d'un script Python. Comme cet outil consomme peu de ressources, il n'affecte pas les performances comme certains autres outils tels que le débogage malloc.

bugreport

bugreport est un outil de journalisation qui vous permet de savoir si votre jeu a planté ou non en raison d'un manque de mémoire. La sortie de l'outil est beaucoup plus détaillée que celle de Logcat. Il est utile pour le débogage de la mémoire, car il indique si votre jeu a planté en raison d'un manque de mémoire ou s'il a été arrêté par le LMK.

Pour en savoir plus, consultez Capturer et lire les rapports de bug.