Je suis assez curieux de cette question concernant la gestion de la mémoire du système d’exploitation de Android , de sorte que je souhaite une description assez détaillée. répondre sur ce sujet.
Ce que j'aimerais savoir:
Et, surtout:
Ce que j'ai entendu jusqu'à présent (jusqu'en 2013):
Ce qui me rend très curieux:
Ces deux limites sont très basses.
Je viens de télécharger le Android Task Manager pour vérifier la mémoire vive 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 le maximum mentionné ci-dessus RAM utilisation de 32 Mo. Alors, comment fait-on Android déterminez combien RAM une application peut utiliser? Comment est-il possible que les applications dépassent cette limite?
De plus, j'ai remarqué que certaines applications de la mine (tuées par le système?) Avec une OutOfMemoryException avec environ 30 à 40 mégaoctets. D'autre part, des applications fonctionnant sur mon téléphone utilisent 100 Mo et plus après un certain temps (probablement à cause de fuites de mémoire) qui ne se bloquent pas ou se faire tuer. Donc , cela dépend évidemment aussi de l'application elle-même lorsqu'il s'agit de déterminer combien RAM peut être épargné. Comment est-ce possible? (j’ai fait mes tests avec un HTC One S avec 768 Mo de RAM)
Avertissement: Je ne suis pas affilié à Android app Task Manager de quelque manière que ce soit.
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()
sur ActivityManager
vous donnera la valeur pour le périphérique sur lequel votre code est exécuté.
Existe-t-il des différences entre les versions Android?)?
Oui, dans la mesure où les exigences du système d’exploitation ont augmenté au fil des ans et que les périphériques doivent être adaptés en conséquence.
Existe-t-il des différences concernant le fabricant de l'appareil?
Oui, dans la mesure où les fabricants fabriquent des appareils et que leur taille varie d’un appareil à l’autre.
Quels "facteurs secondaires" sont pris en compte lorsqu'il s'agit de déterminer combien RAM une application peut utiliser?
Je n'ai aucune idée de ce que "facteurs secondaires" signifie.
Les premiers appareils avaient un plafond par application de 16 Mo; Les appareils ultérieurs ont augmenté cette capacité à 24 ou 32 Mo
C'est à peu près juste. La résolution de l'écran est un facteur déterminant, car les résolutions plus élevées signifient des images bitmap plus grandes. Par conséquent, les tablettes et les téléphones haute résolution ont tendance à avoir des valeurs encore plus élevées. Par exemple, vous verrez des appareils avec des piles de 48 Mo, et je ne serais pas surpris s'il y a des valeurs plus élevées que cela.
Comment est-il possible que les applications dépassent cette limite?
Vous supposez que l'auteur de cette application sait ce qu'il fait. Considérant que l'utilisation de la mémoire d'une application est difficile pour un noyau Android à déterminer , je ne supposerais pas que l'application en question fournit nécessairement des résultats particulièrement précis.
Cela étant dit, le code natif (NDK) n'est pas soumis à la limite de tas. Et, depuis Android 3.0, les applications peuvent demander un "grand tas", généralement dans la plage de centaines de Mo, mais cela est considéré comme une forme médiocre pour la plupart des applications.
De plus, j'ai remarqué que certaines applications de la mine se bloquaient avec une exception OutOfMemoryException lorsqu'elles utilisaient environ 30 à 40 mégaoctets.
Gardez à l'esprit que le Android garbage collector n'est pas un ramasse-miettes compact. L'exception devrait vraiment être CouldNotFindSufficientlyLargeBlockOfMemoryException
, mais cela a probablement été jugé trop verbeux. OutOfMemoryException
signifie que vous ne pouvez pas allouer le bloc demandé , pas que vous ayez complètement épuisé votre tas.
C'est la fin de 2018 alors les choses ont changé.
Tout d’abord: lancez votre application et ouvrez l’onglet Android Profileur dans Android Studio. Vous verrez combien de mémoire il consomme, vous serez surpris mais cela peut allouer beaucoup de RAM.
Aussi voici un excellent article dans la documentation officielle avec des instructions détaillées sur l'utilisation de Memory Profiler, qui peut vous donner un aperçu détaillé de la gestion de votre mémoire.
Mais dans la plupart des cas, votre Android Profiler vous suffira.
Habituellement, une application commence par 50 Mo d’allocation RAM mais saute instantanément à 90 Mo lorsque vous commencez à charger des photos en mémoire. Lorsque vous ouvrez Activité avec ViewPager avec des photos préchargées (3,5 Mo chacune), vous pouvez obtenir 190 Mo facilement 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 d'images (Glide, Picasso) et tout ira bien pour vous.
Mais si vous avez besoin d'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 totale disponible et en calculer une partie prédéterminée (en%). Dans mon cas, je devais mettre en mémoire cache les photos déchiffrées afin de ne pas avoir à les déchiffrer à chaque fois que l'utilisateur glissait dans la liste.
À cette fin, vous pouvez utiliser prêt à l’emploi classe LruCache . Il s'agit d'une classe de cache qui trace automatiquement la quantité de mémoire allouée par vos objets (ou le nombre d'instances) et supprime les plus anciennes pour conserver les données récentes en fonction de leur historique d'utilisation. Voici un excellent tutoriel sur son utilisation.
Dans mon cas, j'ai créé 2 instances de caches: pour les pouces et les pièces jointes. Les a rendus statiques avec un accès singleton afin qu’ils soient disponibles globalement dans 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;
}
}
Voici comment je calcule la disponibilité RAM gratuite et combien 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 Adapters pour obtenir une image en cache:
byte[] decryptedThumbnail = BitmapLruCache.getDecryptedThumbCacheInstance().getBitmap(thumbUri);
et comment je l'ai mis en cache dans le thread d'arrière-plan (AsyncTask ordinaire):
BitmapLruCache.getDecryptedThumbCacheInstance().addBitmap(thumbUri, thumbBytes);
Mon application cible l'API 19+, donc les périphériques ne sont pas anciens et ces portions de RAM disponibles suffisent pour le cache dans mon cas (1% et 3%).
Fait amusant: Android ne dispose d'aucune API ni d'aucun autre hack pour obtenir la quantité de mémoire allouée à votre application, elle est calculée sur la voler en fonction de divers facteurs.
P.S. J'utilise un champ de classe statique pour contenir un cache mais, conformément aux dernières directives de Android, il est recommandé d'utiliser composant d'architecture ViewModel à cette fin.
Les limites de mémoire par application sont définies ici en fonction de la taille de l'écran et Android version: https://drive.google.com/file/d/0B7Vx1OvzrLa3Y0R0X1BZbUpicGc/view?usp=sharing =
Source: Android Téléchargements de compatibilité http://source.Android.com/compatibility/downloads.html ; Document de définition de compatibilité (CDD), section Compatibilité des machines virtuelles ou exécution Compatibilité