87 votes

L'application Android manque de mémoire - tout essayé et toujours perdu

J'ai passé 4 jours à essayer tout ce que je peux comprendre la fuite de mémoire dans une application que je suis en développement, mais les choses cessé de faire sens, il y a longtemps.

L'application que je suis en développement est de nature sociale, alors pensez au profil des Activités de (P) et de la liste des Activités avec les données - par exemple des badges (B). Vous pouvez monter à partir du profil de l'insigne de la liste à d'autres profils, pour d'autres listes, etc.

Imaginez donc un flux comme cette P1 -> B1 -> P2 -> B2 -> P3 -> B3, etc. Pour des raisons de cohérence, je suis le chargement des profils et des insignes de la même utilisateur, de sorte que chaque P page est la même et est donc chaque B page.

L'essentiel du problème est le suivant: après avoir navigué un peu, en fonction de la taille de chaque page, j'obtiens un souvenir d'exception dans des endroits aléatoires - des Bitmaps, des Chaînes, etc -, il ne semble pas être compatible.

Après avoir fait tout ce qui est imaginable de comprendre pourquoi je suis à cours de mémoire, j'en suis venu avec rien. Ce que je ne comprends pas, c'est pourquoi Android n'est pas de tuer P1, B1, etc si elle est à court de mémoire lors du chargement et au lieu des collisions. Je m'attends à ce que ces activités antérieures à mourir et à ressusciter si jamais j'ai de nouveau à eux via onCreate() et onRestoreInstanceState().

Le laisser seul, même si je ne P1 -> B1 -> Retour -> B1 -> Retour -> B1, je reçois toujours un crash. Cela indique une sorte de fuite de mémoire, mais même après dumping hprof et l'utilisation de MAT et JProfiler, je ne peux pas identifier.

J'ai désactivé le chargement des images à partir du web (et augmenté les données d'essai chargé de se rattraper et de faire le test juste) et fait en sorte que l'image cache utilise SoftReferences. Android en fait essaie de libérer les quelques SoftReferences il a, mais juste avant qu'il se bloque de mémoire.

Insigne de pages d'obtenir les données à partir du web, de le charger dans un tableau de EntityData à partir d'un BaseAdapter et le donner à un ListView (je suis en fait en utilisant CommonsWare est excellent MergeAdapter, mais dans ce Badge, il est vraiment seulement 1 adaptateur de toute façon, mais je voulais parler de ce fait de toute façon).

Je suis passé par le code et n'a pas été en mesure de trouver quelque chose qui serait en fuite. J'ai effacé et entaché de nullité de tout ce que j'ai pu trouver et même Système.gc() à gauche et à droite, mais encore l'application se bloque.

Je ne comprends toujours pas pourquoi inactif activités qui sont sur la pile n'obtenez pas moissonnés, et j'aimerais vraiment comprendre.

À ce stade, je suis à la recherche des indices, des conseils, des solutions... tout ce qui pourrait les aider.

Je vous remercie.

106voto

hackbod Points 55292

Je ne comprends toujours pas pourquoi inactif activités qui sont sur la pile n'obtenez pas moissonnés, et j'aimerais vraiment comprendre.

Ce n'est pas la façon dont les choses fonctionnent. La seule gestion de la mémoire que les impacts de l'activité du cycle de vie est le mondial de la mémoire à travers tous les processus, comme Android décide qu'il est faible sur la mémoire et donc le besoin de tuer les processus d'arrière-plan pour obtenir un peu de retour.

Si votre demande est assis au premier plan commence de plus en plus d'activités, il n'est jamais aller dans l'arrière-plan, de sorte qu'il sera toujours frappé son processus local de la limite de mémoire avant que le système ne vient jamais fermer pour le meurtre de son processus. (Et quand il fait tuer son processus, il va tuer le processus d'hébergement de toutes les activités, y compris tout ce qui est actuellement au premier plan.)

Donc, il me semble que votre problème de base est: vous êtes à la laisser trop d'activités à exécuter dans le même temps, et/ou chacun de ces activités est maintenant sur le trop grand nombre de ressources.

Vous avez juste besoin de refonte de votre navigation, de ne pas s'appuyer sur l'empilement d'un nombre arbitraire de potentiellement poids lourds activités. Sauf si vous avez un montant graves de choses dans onStop() (appel d'setContentView() pour effacer l'activité, en vue de la hiérarchie claire et les variables de tout ce qu'elle peut être tenue sur), vous allez juste de manquer de mémoire.

Vous pouvez envisager d'utiliser le nouveau Fragment des Api pour remplacer cet arbitraire de la pile d'activités avec une seule et même activité que de plus en plus étroitement gère sa mémoire. Par exemple, si vous utilisez la pile de retour des installations de fragments, lorsqu'un fragment va sur la pile de retour et n'est plus visible, son onDestroyView() la méthode est appelée pour supprimer complètement son point de vue de la hiérarchie, ce qui réduit considérablement son empreinte.

Maintenant, autant que vous de s'écraser dans le flux de l'endroit où vous appuyez sur la touche back, d'accéder à une activité, appuyez sur retour, passez à une autre activité, etc et n'ont jamais un deep stack, alors oui vous avez juste une fuite. Ce blog décrit comment déboguer des fuites: http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html

21voto

vovkab Points 563

Quelques conseils:

  1. Assurez-vous que vous n'êtes pas de fuite contexte d'activité.

  2. Assurez-vous que vous ne gardez pas les références sur des bitmaps. Nettoyez tous vos ImageView est en Activité#onStop, quelque chose comme ceci:

    Drawable d = imageView.getDrawable();  
    if (d != null) d.setCallback(null);  
    imageView.setImageDrawable(null);  
    imageView.setBackgroundDrawable(null);
    
  3. Recycler les bitmaps si vous n'avez pas besoin de plus.

  4. Si vous utilisez de la mémoire cache, comme la mémoire-lru, assurez vous de ne pas utiliser trop de mémoire.

  5. Non seulement les images de prendre beaucoup de mémoire, assurez-vous de ne pas garder trop d'autres données en mémoire. Cela peut se produire si vous avez infini listes dans votre application. Essayez de mettre en cache des données dans la Base de données.

  6. Sur android 4.2, il y a un bug(stackoverflow#13754876) avec l'accélération matérielle, donc si vous utilisez hardwareAccelerated=true dans votre manifeste, c'est une fuite de mémoire. GLES20DisplayList - maintenez les références, même si vous avez fait l'étape (2) et personne ne fait référence à cette image. Ici, vous devez:

    a) désactiver l'accélération matérielle pour les api, les 16 et 17;
    ou
    b) détacher vue de la tenue de bitmap

  7. Pour Android 3+ vous pouvez essayer d'utiliser l' android:largeHeap="true" votre AndroidManifest. Mais il ne résoudra pas vos problèmes de mémoire, il suffit de reporter.

  8. Si vous avez besoin, comme, une infinité de navigation, puis des Fragments - devrait être votre choix. Si vous avez 1 activité, qui permettra de basculer entre les fragments. De cette façon, vous permettra également de résoudre certains des problèmes de mémoire, comme le numéro 4.

  9. L'utilisation de la Mémoire de l'Analyseur de trouver la cause de votre perte de mémoire.
    Voici une très bonne vidéo de Google I/O 2011: gestion de la Mémoire pour les Applications Android
    Si vous traitez avec des bitmaps ce devrait être un must read: Affichage des images de manière Efficace

4voto

Ed Burnette Points 1017

Les bitmaps sont souvent responsables des erreurs de mémoire sur Android, ce serait donc un domaine à vérifier.

2voto

NewProggie Points 417

Avez-vous des références à chaque activité? Autant que je sache, c’est une raison qui empêche Android de supprimer des activités de la pile.

Êtes-vous en mesure de reproduire cette erreur sur d'autres appareils également? J'ai rencontré un comportement étrange de certains appareils Android en fonction du fabricant de la ROM et / ou du matériel.

1voto

vee Points 470

Essayez de transmettre getApplicationContext () à tout ce qui nécessite un contexte. Vous pouvez avoir une variable globale contenant une référence à vos activités et les empêchant d'être récupérées.

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