162 votes

Quelle est la quantité maximale de RAM qu'une application peut utiliser ?

Je suis assez curieux de cette question concernant le la gestion de la mémoire du système d'exploitation Android J'espère donc une réponse assez détaillée sur ce sujet.

Ce que j'aimerais savoir :

  • Quel est le quantité maximale de mémoire (en mégaoctets / comme pourcentage de la RAM totale) qu'une application Android (qui n'est pas une application système) peut utiliser ?
  • Y a-t-il des différences entre Versions Android ?
  • Y a-t-il des différences concernant le fabricant de l'appareil ?

Et le plus important :

  • Quoi est considéré comme / de quoi cela dépend-il ? lorsqu'il s'agit pour le système de déterminer la quantité de RAM qu'une application peut utiliser au moment de l'exécution (en supposant que la mémoire maximale par application n'est pas un nombre statique) ?

Ce que j'ai entendu jusqu'à présent (jusqu'en 2013) :

  • Les premiers appareils Android avaient un plafond de 16 Mo par application.
  • Plus tard, ce plafond est passé à 24MB ou 32MB.

Ce qui me rend très curieux :

Ces deux limites sont très basses.

J'ai récemment téléchargé le Gestionnaire de tâches Android pour vérifier la RAM de mes appareils. Ce que j'ai remarqué, c'est que certaines applications utilisent environ 40 à 50 mégaoctets de RAM, ce qui est évidemment plus que l'utilisation maximale de RAM mentionnée de disons 32 Mo. Alors, comment Android détermine-t-il la quantité de RAM qu'une application peut utiliser ? Comment est-il possible que des applications dépassent cette limite ?

De plus, j'ai remarqué que certaines de mes applications se plantent (tuées par le système ?) avec un message OutOfMemoryException en utilisant environ 30-40 mégaoctets. D'un autre côté, j'ai des applications fonctionnant sur mon téléphone qui utilisent 100 Mo et plus après un certain temps (probablement en raison de fuites de mémoire) qui ne se plantent pas ou ne sont pas tués. Donc cela dépend évidemment aussi de l'application elle-même lorsqu'il s'agit de déterminer combien de RAM peut être épargnée. Comment cela est-il possible ? (J'ai effectué mes tests avec un HTC One S avec 768 Mo de RAM)

Avertissement : Je ne suis PAS affilié à l'application Android Task Manager de quelque manière que ce soit.

118voto

CommonsWare Points 402670

Quelle est la quantité maximale de mémoire (en mégaoctets / en pourcentage de la RAM totale) qu'une application Android (qui n'est pas une application système) peut utiliser ?

Cela varie selon les appareils. getMemoryClass() en ActivityManager vous donnera la valeur pour le périphérique sur lequel votre code est exécuté.

Y a-t-il des différences entre les versions Android ?

Oui, dans la mesure où les exigences des systèmes d'exploitation ont augmenté au fil des ans et que les appareils doivent s'adapter en conséquence.

Y a-t-il des différences concernant le fabricant de l'appareil ?

Oui, dans la mesure où les fabricants fabriquent des appareils, et que la taille varie selon les appareils.

Quels sont les "facteurs secondaires" pris en considération lorsqu'il s'agit de déterminer la quantité de RAM qu'une application peut utiliser ?

Je n'ai aucune idée de ce que signifie "facteurs secondaires".

Les premiers appareils avaient un plafond de 16 Mo par application ; les appareils ultérieurs ont porté ce plafond à 24 ou 32 Mo.

C'est à peu près ça. La résolution de l'écran est un facteur déterminant, car plus la résolution est grande, plus le bitmap est important. Les tablettes et les téléphones à haute résolution auront donc tendance à avoir des valeurs plus élevées. Par exemple, vous verrez des appareils avec des tas de 48 Mo, et je ne serais pas surpris qu'il y ait des valeurs supérieures à cela.

Comment est-il possible que des applications dépassent cette limite ?

Vous supposez que l'auteur de cette application sait ce qu'il fait. En considérant que l'utilisation de la mémoire d'une application est difficile à déterminer pour un ingénieur Android de base Je ne pense pas que l'application en question fournisse nécessairement des résultats particulièrement précis.

Cela dit, le code natif (NDK) n'est pas soumis à la limite du tas. Et, depuis Android 3.0, les applications peuvent demander un "grand tas", généralement de l'ordre de plusieurs centaines de Mo, mais cela est considéré comme une mauvaise habitude pour la plupart des applications.

En outre, j'ai remarqué que certaines de mes applications se plantent avec une exception OutOfMemoryException lorsqu'elles utilisent environ 30-40 mégaoctets.

Gardez à l'esprit que le ramasseur de déchets d'Android n'est pas un ramasseur de déchets compactant. L'exception doit vraiment être CouldNotFindSufficientlyLargeBlockOfMemoryException mais cela a probablement été jugé trop verbeux. OutOfMemoryException signifie que vous n'a pas pu allouer le bloc demandé et non pas que vous ayez épuisé votre tas.

18voto

Kirill Karmazin Points 959

Nous sommes à la fin de l'année 2018, les choses ont donc changé.

Tout d'abord, lancez votre application et ouvrez l'onglet Android Profiler dans Android Studio. Vous verrez combien de mémoire elle consomme, vous serez surpris mais elle peut allouer beaucoup de RAM.

Aussi Voici un excellent article dans les docs officiels avec des instructions détaillées sur la façon d'utiliser le Memory Profiler qui peut vous donner un aperçu en profondeur de votre gestion de la mémoire.

Mais dans la plupart des cas, votre Android Profiler habituel sera suffisant pour vous.

enter image description here

En général, une application commence avec une allocation de 50 Mo de RAM, mais elle passe instantanément à 90 Mo lorsque vous commencez à charger des photos en mémoire. Lorsque vous ouvrez Activity avec un ViewPager contenant des photos préchargées (3,5 Mo chacune), vous pouvez obtenir 190 Mo en quelques secondes.

Mais cela ne signifie pas que vous avez des problèmes de gestion de la mémoire.

Le meilleur conseil que je puisse donner est de suivre les directives et les meilleures pratiques, d'utiliser les meilleures bibliothèques pour le chargement des images (Glide, Picasso) et tout ira bien.


Mais si vous devez adapter quelque chose et que vous avez vraiment besoin de savoir combien de mémoire vous pouvez allouer manuellement, vous pouvez obtenir la mémoire libre totale et calculer une portion prédéterminée (en %) de celle-ci. Dans mon cas, j'avais besoin de mettre en cache les photos décryptées en mémoire pour ne pas avoir à les décrypter à chaque fois que l'utilisateur glisse dans la liste.

Pour ce faire, vous pouvez utiliser des produits prêts à l'emploi Classe LruCache . Il s'agit d'une classe de cache qui suit automatiquement la quantité de mémoire allouée par vos objets (ou le nombre d'instances) et supprime les plus anciens pour conserver les plus récents en fonction de leur historique d'utilisation. Voici un excellent tutoriel sur la façon de l'utiliser.

Dans mon cas, j'ai créé 2 instances de caches : pour les vignettes et les pièces jointes. Je les ai rendues statiques avec un accès singleton pour qu'elles soient disponibles globalement dans toute l'application.

classe de cache :

public class BitmapLruCache extends LruCache<Uri, byte[]> {

    private static final float CACHE_PART_FOR_THUMBS_PRC = 0.01f; // 1% (Nexus 5X - 5Mb)
    private static final float CACHE_PART_FOR_ATTACHMENTS_PRC = 0.03f;// 3% (Nexus 5X - 16Mb)
    private static BitmapLruCache thumbCacheInstance;
    private static BitmapLruCache attachmentCacheInstance;

public static synchronized BitmapLruCache getDecryptedThumbCacheInstance() {
    if (thumbCacheInstance == null) {

        int cacheSize = getCacheSize(CACHE_PART_FOR_THUMBS_PRC);
    //L.log("creating BitmapLruCache for Thumb with size: " + cacheSize + " bytes");
        thumbCacheInstance = new BitmapLruCache(cacheSize);
        return thumbCacheInstance;
    } else {
        return thumbCacheInstance;
    }
}

public static synchronized BitmapLruCache getDecryptedAttachmentCacheInstance() {
    if (attachmentCacheInstance == null) {

        int cacheSize = getCacheSize(CACHE_PART_FOR_ATTACHMENTS_PRC);
    //            L.log("creating BitmapLruCache for Attachment with size: " + cacheSize + " bytes");
        attachmentCacheInstance = new BitmapLruCache(cacheSize);
        return attachmentCacheInstance;
    } else {
        return attachmentCacheInstance;
    }
}

private BitmapLruCache(int maxSize) {
    super(maxSize);
}

public void addBitmap(Uri uri, byte[] bitmapBytes) {
    if (get(uri) == null && bitmapBytes != null)
        put(uri, bitmapBytes);
}

public byte[] getBitmap(Uri uri) {
    return get(uri);
}

@Override
protected int sizeOf(Uri uri, byte[] bitmapBytes) {
    // The cache size will be measured in bytes rather than number of items.
    return bitmapBytes.length;
}
}

C'est ainsi que je calcule la RAM libre disponible et la quantité que je peux en tirer :

private static int getCacheSize(float partOfTotalFreeMemoryToUseAsCache){
    final long maxMemory = Runtime.getRuntime().maxMemory();
    //Use ... of available memory for List Notes thumb cache
    return (int) (maxMemory * partOfTotalFreeMemoryToUseAsCache);
}

Et voici comment je l'utilise dans les adaptateurs pour obtenir une image en cache :

byte[] decryptedThumbnail = BitmapLruCache.getDecryptedThumbCacheInstance().getBitmap(thumbUri);

et comment je le mets en cache dans le fil d'arrière-plan (AsyncTask ordinaire) :

BitmapLruCache.getDecryptedThumbCacheInstance().addBitmap(thumbUri, thumbBytes); 

Mon application vise l'API 19+, les appareils ne sont donc pas vieux et ces portions de RAM disponible sont suffisantes pour le cache dans mon cas (1% et 3%).

Fait amusant : Android ne dispose pas d'API ou d'autres astuces pour obtenir la quantité de mémoire allouée à votre application, elle est calculée à la volée en fonction de divers facteurs.


P.S. J'utilise un champ de classe statique pour contenir un cache, mais selon les dernières directives Android, il est recommandé d'utiliser Composant de l'architecture ViewModel à cette fin.

11voto

Les limites de mémoire par application sont ici fonction de la taille de l'écran et de la version d'Android : https://drive.google.com/file/d/0B7Vx1OvzrLa3Y0R0X1BZbUpicGc/view?usp=sharing

Source : Téléchargements de compatibilité Android http://source.Android.com/compatibility/downloads.html ; Document de définition de la compatibilité (CDD), section Compatibilité avec les machines virtuelles ou compatibilité avec le temps d'exécution.

3voto

Gouz Points 320

En ce moment, je travaille sur une application et le Samsung Ultra S21 que j'utilise (même s'il dispose de 16 Go de RAM) ne me permet pas d'utiliser plus de 500 Mo pour cette application, même avec Android:largeHeap="true" dans le manifeste.

1voto

Lothar Points 4740

Il n'y a plus de limite, du moins si vous optez pour le NDK. Pourquoi le serait-elle ? Rappelez-vous qu'Android est historiquement issu du monde des appareils embarqués où chaque application avait des tâches simples à accomplir, interdisant souvent toute utilisation dynamique de la mémoire.

Il n'était pas considéré comme un système à usage général. Nous pouvons encore voir beaucoup d'artefacts de conception de ces temps anciens qui n'ont jamais eu de sens sur un "vrai ordinateur" et c'est une raison pour laquelle iOS a tant de meilleures applications qu'Android, il a été conçu beaucoup mieux et plus facile à programmer pour les tâches dirigées par l'utilisateur.

Lors de la conception d'une application, il est important que votre activité réagisse bien aux signaux "onLowMemory".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X