Comment détecter par programme la taille du tas d'application disponible pour une application Android?
J'ai entendu dire qu'il y a une fonction qui fait cela dans les versions ultérieures du SDK. Dans tous les cas, je recherche une solution qui fonctionne pour la version 1.5 et plus.
android
memory
heap
heap-memory
hpique
la source
la source
Réponses:
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: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:
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 dansgetMemoryClass()
(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()
etgetMemoryClass()
pour quatre appareils différents exécutant CyanogenMod, en utilisant deux valeurs de tas différentes (définies manuellement) pour chacun: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:
Aussi (par Kishore dans un commentaire ci-dessous):
Et (d'après le commentaire d'akauppi):
Par un commentaire de cmcromance:
Et (d'après les commentaires de Tencent):
Autres appareils
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 laissantgetMemoryClass()
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 pargetMemoryClass()
. 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 cycleonStop()
/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 quigetMemoryClass()
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 queonStop()
/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 lamaxMemory()
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 quimaxMemory()
est autorisé.la source
L' API officielle est:
la source
Debug.getNativeHeapSize()
fera l'affaire, je devrais penser. Il existe depuis la version 1.0, cependant.La
Debug
classe dispose de nombreuses méthodes intéressantes pour suivre les allocations et autres problèmes de performances. De plus, si vous devez détecter une situation de mémoire insuffisante, vérifiezActivity.onLowMemory()
.la source
Voici comment procéder:
Obtenir la taille maximale du tas que l'application peut utiliser:
Obtenir la part du tas que votre application utilise actuellement:
Obtenir la quantité de tas que votre application peut désormais utiliser (mémoire disponible):
Et, pour bien formater chacun d'eux, vous pouvez utiliser:
la source
Cela renvoie la taille maximale du tas en octets:
J'utilisais ActivityManager.getMemoryClass () mais sur CyanogenMod 7 (je ne l'ai pas testé ailleurs), il renvoie une valeur incorrecte si l'utilisateur définit la taille du tas manuellement.
la source
getMemoryClass
semble impliquer que le nombre peut ne pas être le même que la taille de tas disponible pour votre vm, et puisque la documentation pourgetNativeHeapSize
est ... taciturne, je pense vraiment queRuntime.getRuntime().maxMemory()
c'est la meilleure réponse.Certaines opérations sont plus rapides que le gestionnaire d'espace de tas Java. Retarder les opérations pendant un certain temps peut libérer de l'espace mémoire. Vous pouvez utiliser cette méthode pour éviter l'erreur de taille de tas:
la source
AvailableMemoryPercentage
est selon la formule: combien de mémoire de l'appareil est actuellement libre.MIN_AVAILABLE_MEMORY_PERCENTAGE
est votre paramètre personnalisé, un seuil à partir duquel vous commencez à attendre que le garbage collector fasse son travail.Asus Nexus 7 (2013) 32Gig: getMemoryClass () = 192 maxMemory () = 201326592
J'ai fait l'erreur de prototyper mon jeu sur le Nexus 7, puis de découvrir qu'il manquait de mémoire presque immédiatement sur la tablette générique 4.04 de ma femme (memoryclass 48, maxmemory 50331648)
J'aurai besoin de restructurer mon projet pour charger moins de ressources lorsque je déterminerai que la classe de mémoire est faible.
Existe-t-il un moyen en Java de voir la taille actuelle du tas? (Je peux le voir clairement dans le logCat lors du débogage, mais j'aimerais un moyen de le voir dans le code pour s'adapter, comme si currentheap> (maxmemory / 2) déchargez des bitmaps de haute qualité chargent de faible qualité
la source
Voulez-vous dire par programme ou juste pendant le développement et le débogage? Dans ce dernier cas, vous pouvez voir ces informations du point de vue DDMS dans Eclipse. Lorsque votre émulateur (peut-être même un téléphone physique branché) est en cours d'exécution, il répertorie les processus actifs dans une fenêtre sur la gauche. Vous pouvez le sélectionner et il existe une option pour suivre les allocations de tas.
la source
la valeur est b
la valeur est Mo
la source
rt
? Où est-il déclaré?