Il y a deux façons de penser à votre expression "taille du tas d'application disponible":
Combien de tas mon application peut-elle utiliser avant qu'une erreur matérielle ne se déclenche? Et
Quelle quantité de tas mon application doit -elle utiliser, compte tenu des contraintes de la version du système d'exploitation Android et du matériel de l'appareil de l'utilisateur?
Il existe une méthode différente pour déterminer chacun des éléments ci-dessus.
Pour l'élément 1 ci-dessus: maxMemory()
qui peut être invoqué (par exemple, dans la onCreate()
méthode de votre activité principale ) comme suit:
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));
Cette méthode vous indique le nombre total d' octets de tas que votre application est autorisée à utiliser.
Pour le point 2 ci-dessus: getMemoryClass()
qui peut être invoqué comme suit:
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass();
Log.v("onCreate", "memoryClass:" + Integer.toString(memoryClass));
Cette méthode vous indique approximativement le nombre de mégaoctets de tas que votre application doit utiliser si elle veut être correctement respectueuse des limites de l'appareil actuel et des droits des autres applications à s'exécuter sans être forcées à plusieurs reprises dans le cycle onStop()
/ onResume()
car elles sont grossièrement vidé de la mémoire pendant que votre application éléphantine prend un bain dans le jacuzzi Android.
Cette distinction n'est pas clairement documentée, pour autant que je sache, mais j'ai testé cette hypothèse sur cinq appareils Android différents (voir ci-dessous) et j'ai confirmé à ma propre satisfaction qu'il s'agit d'une interprétation correcte.
Pour une version standard d'Android, maxMemory()
retournera généralement environ le même nombre de mégaoctets que ceux indiqués dans getMemoryClass()
(c'est- à -dire, environ un million de fois cette dernière valeur).
La seule situation (dont je suis conscient) pour laquelle les deux méthodes peuvent diverger est sur un appareil enraciné exécutant une version Android telle que CyanogenMod, qui permet à l'utilisateur de sélectionner manuellement la taille du tas qui doit être autorisée pour chaque application. Dans CM, par exemple, cette option apparaît sous "Paramètres CyanogenMod" / "Performance" / "Taille du tas VM".
REMARQUE: SACHEZ QUE RÉGLER CETTE VALEUR MANUELLEMENT PEUT MESSER VOTRE SYSTÈME, SURTOUT si vous sélectionnez une valeur plus petite que la normale pour votre appareil.
Voici les résultats de mes tests montrant les valeurs renvoyées par maxMemory()
et getMemoryClass()
pour quatre appareils différents exécutant CyanogenMod, en utilisant deux valeurs de tas différentes (définies manuellement) pour chacun:
- G1:
- Avec la taille du segment de mémoire VM définie sur 16 Mo:
- maxMemory: 16777216
- getMemoryClass: 16
- Avec la taille du segment de mémoire VM définie sur 24 Mo:
- maxMemory: 25165824
- getMemoryClass: 16
- Moto Droid:
- Avec la taille du segment de mémoire VM définie sur 24 Mo:
- maxMemory: 25165824
- getMemoryClass: 24
- Avec la taille du segment de mémoire VM définie sur 16 Mo:
- maxMemory: 16777216
- getMemoryClass: 24
- Nexus One:
- Avec une taille de segment de mémoire virtuelle définie sur 32 Mo:
- maxMemory: 33554432
- getMemoryClass: 32
- Avec une taille de segment de mémoire VM définie sur 24 Mo:
- maxMemory: 25165824
- getMemoryClass: 32
- Viewsonic GTab:
- Avec VM Heap Size défini sur 32:
- maxMemory: 33554432
- getMemoryClass: 32
- Avec VM Heap Size défini sur 64:
- maxMemory: 67108864
- getMemoryClass: 32
En plus de ce qui précède, j'ai testé sur une tablette Novo7 Paladin exécutant Ice Cream Sandwich. Il s'agissait essentiellement d'une version stock d'ICS, sauf que j'ai rooté la tablette via un processus simple qui ne remplace pas l'ensemble du système d'exploitation, et en particulier ne fournit pas d'interface permettant d'ajuster manuellement la taille du tas.
Pour cet appareil, voici les résultats:
- Novo7
- maxMemory: 62914560
- getMemoryClass: 60
Aussi (par Kishore dans un commentaire ci-dessous):
- HTC One X
- maxMemory: 67108864
- getMemoryClass: 64
Et (d'après le commentaire d'akauppi):
- Samsung Galaxy Core Plus
- maxMemory: (Non spécifié dans le commentaire)
- getMemoryClass: 48
- largeMemoryClass: 128
Par un commentaire de cmcromance:
- Grand tas Galaxy S3 (Jelly Bean)
- maxMemory: 268435456
- getMemoryClass: 64
Et (d'après les commentaires de Tencent):
- LG Nexus 5 (4.4.3) normal
- maxMemory: 201326592
- getMemoryClass: 192
- LG Nexus 5 (4.4.3) gros tas
- maxMemory: 536870912
- getMemoryClass: 192
- Galaxy Nexus (4.3) normal
- maxMemory: 100663296
- getMemoryClass: 96
- Grand tas de Galaxy Nexus (4.3)
- maxMemory: 268435456
- getMemoryClass: 96
- Galaxy S4 Play Store Edition (4.4.2) normal
- maxMemory: 201326592
- getMemoryClass: 192
- Grand tas de Galaxy S4 Play Store Edition (4.4.2)
- maxMemory: 536870912
- getMemoryClass: 192
Autres appareils
- Huawei Nexus 6P (6.0.1) normal
- maxMemory: 201326592
- getMemoryClass: 192
Je n'ai pas testé ces deux méthodes en utilisant l'option manifeste spéciale android: largeHeap = "true" disponible depuis Honeycomb, mais grâce à cmcromance et tencent, nous avons quelques exemples de valeurs largeHeap, comme indiqué ci-dessus.
Mon attente (qui semble être prise en charge par les nombres de largeHeap ci-dessus) serait que cette option aurait un effet similaire à la configuration manuelle du tas via un système d'exploitation enraciné - c'est-à-dire qu'elle augmenterait la valeur de maxMemory()
tout en laissant getMemoryClass()
seul. Il existe une autre méthode, getLargeMemoryClass (), qui indique la quantité de mémoire autorisée pour une application à l'aide du paramètre largeHeap. La documentation de getLargeMemoryClass () indique que "la plupart des applications ne devraient pas avoir besoin de cette quantité de mémoire et devraient plutôt rester avec la limite de getMemoryClass ()."
Si j'ai bien deviné, utiliser cette option aurait les mêmes avantages (et risques) que l'utilisation de l'espace rendu disponible par un utilisateur qui a augmenté le tas via un système d'exploitation enraciné (c'est-à-dire, si votre application utilise la mémoire supplémentaire, il ne jouera probablement pas aussi bien avec toutes les autres applications que l'utilisateur exécute en même temps).
Notez que la classe de mémoire n'a apparemment pas besoin d'être un multiple de 8 Mo.
Nous pouvons voir de ce qui précède que le getMemoryClass()
résultat est inchangé pour une configuration de périphérique / OS donnée, tandis que la valeur maxMemory () change lorsque le tas est défini différemment par l'utilisateur.
Ma propre expérience pratique est que sur le G1 (qui a une classe de mémoire de 16), si je sélectionne manuellement 24 Mo comme taille de tas, je peux exécuter sans erreur même si mon utilisation de la mémoire est autorisée à dériver vers 20 Mo (vraisemblablement cela pourrait aller jusqu'à 24 Mo, même si je n'ai pas essayé cela). Mais d'autres applications de même taille peuvent être vidées de la mémoire en raison de la pigmentation de ma propre application. Et, inversement, mon application peut être vidée de la mémoire si ces autres applications nécessitant beaucoup de maintenance sont mises au premier plan par l'utilisateur.
Ainsi, vous ne pouvez pas dépasser la quantité de mémoire spécifiée par maxMemory()
. Et vous devriez essayer de rester dans les limites spécifiées par getMemoryClass()
. Une façon de faire cela, si tout le reste échoue, pourrait être de limiter les fonctionnalités de ces périphériques de manière à économiser la mémoire.
Enfin, si vous prévoyez de dépasser le nombre de mégaoctets spécifié dans getMemoryClass()
, mon conseil serait de travailler longtemps et dur sur la sauvegarde et la restauration de l'état de votre application, afin que l'expérience de l'utilisateur soit pratiquement ininterrompue si un cycle onStop()
/ onResume()
se produit.
Dans mon cas, pour des raisons de performances, je limite mon application aux appareils exécutant la version 2.2 et supérieure, ce qui signifie que presque tous les appareils exécutant mon application auront une memoryClass de 24 ou plus. Je peux donc concevoir pour occuper jusqu'à 20 Mo de tas et être assez confiant que mon application fonctionnera bien avec les autres applications que l'utilisateur peut exécuter en même temps.
Mais il y aura toujours quelques utilisateurs rootés qui ont chargé une version 2.2 ou supérieure d'Android sur un appareil plus ancien (par exemple, un G1). Lorsque vous rencontrez une telle configuration, idéalement, vous devriez réduire votre utilisation de la mémoire, même si maxMemory()
cela vous dit que vous pouvez aller beaucoup plus haut que les 16 Mo qui getMemoryClass()
vous indiquent que vous devriez cibler. Et si vous ne pouvez pas garantir de manière fiable que votre application respectera ce budget, assurez-vous au moins que onStop()
/ onResume()
fonctionne de manière transparente.
getMemoryClass()
, comme indiqué par Diane Hackborn (hackbod) ci-dessus, n'est disponible qu'au niveau de l'API 5 (Android 2.0), et donc, comme elle le conseille, vous pouvez supposer que le matériel physique de tout appareil exécutant une version antérieure du système d'exploitation est conçu pour prendre en charge de manière optimale les applications n'occupant pas plus de 16 Mo d'espace de stockage.
En revanche, maxMemory()
selon la documentation, est disponible toute l'arrière jusqu'au niveau de l' API 1. maxMemory()
, sur une version pré-2.0, retournera probablement une valeur de 16 Mo, mais je fais voir que dans mes (beaucoup plus tard) versions de CyanogenMod l'utilisateur peut sélectionner une valeur de tas aussi basse que 12 Mo, ce qui entraînerait vraisemblablement une limite de tas inférieure, et je vous suggère donc de continuer à tester la maxMemory()
valeur, même pour les versions du système d'exploitation antérieures à 2.0. Vous devrez peut-être même refuser de s'exécuter dans le cas improbable où cette valeur serait même inférieure à 16 Mo, si vous devez avoir plus que ce qui maxMemory()
est autorisé.