IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Android Discussion :

Fuite mémoire - dalvikvm-heap


Sujet :

Android

  1. #1
    Membre régulier
    Homme Profil pro
    Inscrit en
    Juillet 2012
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2012
    Messages : 89
    Points : 86
    Points
    86
    Par défaut Fuite mémoire - dalvikvm-heap
    Bonjour,

    lors du chargement d'une image, après plusieurs lancements de la même application, l'application crashe avec comme erreur : "Java.lang.OutOfMemoryError".

    J'ai cru comprendre que les images n'étaient pas chargées au même endroit que les autres ressources du code, mais je ne comprends pas comment pallier le problème.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    public void deinitPicture()
    {
      _referencePicture.destroyDrawingCache(); // ne marche pas, la memory heap
                                               // grandit quand meme a chaque nouvelle ouverture/fermeture de l'application
      _referencePicture = null; // pas utile parce que fait par la VM ?
    }
    Merci de vos réponses

  2. #2
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Bonjour,

    Avant de se lancer dans du code d'optimisation (qui ne fera que décaler le problème et non le résoudre), il faut trouver d'ou vient le memory-leak...
    Et là on n'a pas beaucoup de code pour le deviner...
    Ce qu'il faut savoir c'est qu'une application n'est pas quittée de suite quand la dernière activité est fermée... donc toutes les statiques, tous les threads peuvent créer des memory-leaks inattendus si il ne sont pas bien gérés... Le plus "classique" des memory leak, est l'utilisation d'un context en statiques..

    Le GC de dalvik tourne sensiblement comme les autres GC
    http://dubroy.com/blog/google-io-mem...-android-apps/
    N'oubliez pas de cliquer sur mais aussi sur si un commentaire vous a été utile !
    Et surtout

  3. #3
    Membre régulier
    Homme Profil pro
    Inscrit en
    Juillet 2012
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2012
    Messages : 89
    Points : 86
    Points
    86
    Par défaut
    Bonjour,
    J'ai trouvé un moyen de 'détruire' l'image, mais je ne suis pas certain que ce soit le bon.
    Au final, l'application ne plante plus en tout cas :

    je vous donne ma solution :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public void deinitPicture()
    {
      _referencePicture.setImageResource(0);
      // au lieu de _referencePicture.destroyDrawingCache
    }
    et le memory leak vient de l'initialisation/désinitialisation de l'image. En gros, ça buggait juste après initPicture() qui fait juste un _referencePicture.setImageResource(R.drawable.XXXX);
    Le problème venait du fait que en quittant l'appli, l'image n'était pas détruite, j'ai donc résolu avec le SetimageResource(0) lorsque je quitte l'appli, mais je pense qu'il existe d'autres moyens (destroyDrawingCache reste mystérieux pour moi, je pensais justement que c'était ce qu'il me fallait, mais je m'en sors autrement ).
    A savoir, je n'ai plus de fuite de mémoire avec l'appel à setImageResource(0).

    Merci tout de même

  4. #4
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Je continue de penser qu'il y a toujours un memory-leak....

    Une image (j'imagine de type "Bitmap") est un "holder" vers un tableau de byte (byte[])... Ce tableau peut être désalloué à tout moment en appelant Bitmap.recycle(), mais bien entendu, l'objet Bitmap ne peut plus être utilisé par la suite...

    Le GC s'occupe de ça tout seul comme un grand si il n'y a plus de référence à la Bitmap... donc si le faire à la main est utile quand on travaille avec une dizaine de grosses bitmap, il ne servira à rien pour un problème de memory-leak... pour la bonne raison est que ce tableau de byte[] n'est référencé *que* par Bitmap donc même si on appelle "recycle", on va continuer de leaker l'objet "Bitmap", et c'est *ca* qu'il faut corriger... d'autant qu'en général, ce n'est pas l'objet "Bitmap" qui est leaké, mais la vue (et donc tout le contexte avec l'activité). Et avec aussi peu de code, il est difficile d'aider....
    N'oubliez pas de cliquer sur mais aussi sur si un commentaire vous a été utile !
    Et surtout

  5. #5
    Membre régulier
    Homme Profil pro
    Inscrit en
    Juillet 2012
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2012
    Messages : 89
    Points : 86
    Points
    86
    Par défaut
    Argh ui en effet, j'ai encore une fuite de mémoire (Grow Heap (frag case) to 36.368MB) et la fois d'après, j'ai Grow Heap (frag case) to 36.371MB et ça monte de 0.003 MB à chaque lancement de l'application...

    et pour avoir plus de détails d'un point de vue code, c'est en fait une ImageView et non une Bitmap qui bouffe ma mémoire petit à petit.

    Voila l'extrait du LogCat :

    08-17 15:58:05.760: E/AndroidRuntime(28464): java.lang.OutOfMemoryError
    08-17 15:58:05.760: E/AndroidRuntime(28464): at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
    08-17 15:58:05.760: E/AndroidRuntime(28464): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:577)
    08-17 15:58:05.760: E/AndroidRuntime(28464): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:445)
    08-17 15:58:05.760: E/AndroidRuntime(28464): at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:775)
    08-17 15:58:05.760: E/AndroidRuntime(28464): at android.content.res.Resources.loadDrawable(Resources.java:1968)
    08-17 15:58:05.760: E/AndroidRuntime(28464): at android.content.res.Resources.getDrawable(Resources.java:677)
    08-17 15:58:05.760: E/AndroidRuntime(28464): at android.widget.ImageView.resolveUri(ImageView.java:542)
    08-17 15:58:05.760: E/AndroidRuntime(28464): at android.widget.ImageView.setImageResource(ImageView.java:315)

    (ceci ce fait lorsque je fait un ImageView.setresource(R.id.xx)... Effectivement je ne sais pas d'où ça vient, et le fait de mettre la ressource à zéro a juste permis de réduire significativement la fuite de mémoire à chaque pas.. je ne sais pas comment la supprimer en entier


    Pour encore plus de précision niveau Code, j'ai une Activity qui possède un GUIManager (qui s'occupe de toute l'interface graphique), et c'est dans cette classe que je fais initPicture() et deinitPicture() qui set la bonne ressource à l'image.

  6. #6
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Le OOM arrive pour dire, "c'est trop tard, y a eu trop de leak"....

    Mais il nous faudrait du code pour chercher... par exemple, le GUIManager (???) me semble un bon début...

    Ensuite, c'est simple....
    Lancer 3 fois l'appli
    Faire un memory-dump (dans le DDMS il y a un bouton pour ca).
    Et regarder les objets instanciés à soi (en partant par exemple des ImageView encore instancés, et voir qui les maintient en vie)

    Si MAT est installé dans Eclipse, le dump va automatique l'ouvrir
    Aller directement à l'acceuil, puis histogram
    Et taper dans le champ en dessous de "Class Name" le nom du package
    Et bim, il y aura toutes les instances des classes "à soi"
    N'oubliez pas de cliquer sur mais aussi sur si un commentaire vous a été utile !
    Et surtout

  7. #7
    Membre régulier
    Homme Profil pro
    Inscrit en
    Juillet 2012
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2012
    Messages : 89
    Points : 86
    Points
    86
    Par défaut
    la fonction qui charge l'image de référence :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     public void loadReferencePitcure()
        {
        	// secure test
        	if ( _referencePicture == null )
        	{
        		return;
        	}
        	switch ( _idStep )
        	{
        		case 1:
        			// no need of a reference picture for step 1
        			//_referencePicture.setImageResource(R.drawable.laine);
        			break;
     
        		case 2:
        			_referencePicture.setImageResource(R.drawable.or);
        			break;
     
        		case 3:
        			_referencePicture.setImageResource(R.drawable.lin);
        			break;
        	}
     
        	// picture is hidden at beginning
        	//_referencePicture.setAlpha(0.0f); 
        	setAlphaOfView(_referencePicture,0.0f);
        }
    la fonction d'init :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     public void initPicture()
        {
        	// secure test
        	if ( _overlayView == null )
        	{
        		return;
        	}
        	Log.i(TAG,"initPicture");
        	// init the picture
        	_referencePicture = (ImageView) _overlayView.findViewById(R.id.referenceImage);
     
        	// load the good picture depending on the idStep
        	loadReferencePitcure();
        }
    le constructeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public GUIManager(Context context, int idStep, Activity activity)
        {
            // la vue
            _overlayView = View.inflate(context,R.layout.main, null);
     
             // l'etape courrante
             _idStep = idStep;
     
             // l'activite 'mère'
            _activity = activity;
     
            _GUIMainActivityHandler = new Handler()
            {
            	@Override
                public void handleMessage(Message msg)
            	{
            		// update GUI from the good thread
            		updateText();
            	}
            };
        }
    Tout le code est extrait de mon GUIManager, et je pense bien que la fuite de mémoire intervient dans le loadReferencePicture...
    la fonction setAlphaOfView est simplement une fonction qui change le Alpha, mais vu que ceci n'est valable que depuis l'API 11, je veux que mon appli puisse aussi tourner sur des "plus anciens" portables, et donc le code ressemble à ça (avec le @TargetApi qui est important juste pour comprendre) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        @TargetApi(11)
        public void setAlphaOfView(View v, float f)
        {
        	v.setAlpha(f);
        }

  8. #8
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    pourquoi ne pas utiliser setVisibility pour cacher l'image ?

    Alors sinon, il manque un truc primoriale:
    La déclaration du GUIManager, et surtout de _referencePicture...

    En général "_" signifie une statique privée....
    Mais bon... il y a un



    Si j'ai bien compris, tu as plusieurs application qui "partagent" le même bahavior au niveau GUI d'ou l'utilisation d'un GUIManager... c'est ca ? Pourquoi l'héritage d'une classe commune ne peut-elle pas marcher ?
    Quels sont les liens entre l'Activité (dont on connait la "durée de vie") et le GUIManager ?
    N'oubliez pas de cliquer sur mais aussi sur si un commentaire vous a été utile !
    Et surtout

  9. #9
    Membre régulier
    Homme Profil pro
    Inscrit en
    Juillet 2012
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2012
    Messages : 89
    Points : 86
    Points
    86
    Par défaut
    Bonjour,

    Alors j'ai en effet mis un setVisibility maintenant plutot que de changer le alpha (plus facile pour avoir une appli comptable avec des versions plus vieilles d'Android).

    Par contre, j'ai toujours une fuite mémoire :
    voici les codes de mes déclarations :
    pour le GUIManager :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
        public GUIManager(Context context, int idStep)
        {
            _overlayView = View.inflate(context,R.layout.main, null);
            _idStep = idStep;
     
            _GUIMainActivityHandler = new Handler()
            {
            	@Override
                public void handleMessage(Message msg)
            	{
            		// update GUI from the good thread
            		updateGUI();
            	}
            };
        }
    et pour la _referencePicture (dans le GUIManager : )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
          public void initPicture()
        {
        	// secure test
        	if ( _overlayView == null )
        	{
        		return;
        	}
        	Log.i(TAG,"initPicture");
        	// init the picture
        	_referencePicture = (ImageView) _overlayView.findViewById(R.id.referenceImage);
     
        	// load the good picture depending on the idStep
        	loadReferencePitcure();
        }
    Le lien entre l'activité et le guimanager est simple : l'activité a 1 GUIManager, et j'ai séparé en classe non pas pour avoir un GUIManager 'générique', mais simplement pour bien séparer la partie interface graphique du reste de l'appli.
    (la fuite mémoire n'est pas énorme, mais à chaque fois que je relance l'appli, dalvikvm_heap renvoie en Information dans LogCat : "Grow Heap (frag case) to XXXX MB", et ce XXXX grossit de 3Kb par lancement de l'appli...

  10. #10
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Bon.. et bien fait un memory dump du process de ton appli apres une dizaine de lancements....
    Ouvre avec MAT le fichier hprof en "histogramme"
    et restreint les classes affichées à ton package... déjà tu verras quelles classes (à toi) restent instanciées... qui les référence, etc...

    Ensuite, séparer UI du reste, c'est une bonne idée... sauf que Activity c'est déjà de l'UI, donc la partie UI c'est Activity, et c'est la "business logic" du code qu'il faut séparer...

    Si tu pouvais poster l'ensemble des deux fichiers Activity & GUIManager... on verrait peut-être une subtilité
    N'oubliez pas de cliquer sur mais aussi sur si un commentaire vous a été utile !
    Et surtout

Discussions similaires

  1. Créer une fuite mémoire (OutOfMemoryError: Java heap space)
    Par spiffou92 dans le forum Débuter avec Java
    Réponses: 12
    Dernier message: 03/02/2015, 13h45
  2. [tomcat][memoire] java.net.URL et fuite mémoire
    Par Seiya dans le forum Tomcat et TomEE
    Réponses: 6
    Dernier message: 09/03/2009, 10h41
  3. Outil de recherche de fuite mémoire
    Par eag35 dans le forum MFC
    Réponses: 4
    Dernier message: 02/02/2005, 12h46
  4. [SWT]SWT et fuite mémoire(ou pas)
    Par menuge dans le forum SWT/JFace
    Réponses: 2
    Dernier message: 22/06/2004, 21h40
  5. [debug] fuites mémoires
    Par tmonjalo dans le forum C
    Réponses: 3
    Dernier message: 28/07/2003, 17h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo