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

Interfaces Graphiques en Java Discussion :

PB Memoire - Coup de Gueule


Sujet :

Interfaces Graphiques en Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Mars 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2008
    Messages : 23
    Par défaut PB Memoire - Coup de Gueule
    Bonjour a tous,
    je tenais a faire part d'un petit mécontentement sur les "memory leak",
    Non pas au fonctionnement de Java mais surtout au méthodes d'apprentissage de JAVA.
    En effet, je viens de me rendre compte tout récemment, après développement d'une appli graphique basée sur OpemMap, que j'ai énormément de "memory leak".
    Mon coup de gueule, c'est juste le fait que je "croyais" que le GC détruisais tout après fermeture de frame par exemple.
    Hors apreè multiples recherches, utilisations de profiler (TPTP), je suis dans l'incapacité de déréférencer totalement les fenêtres filles, et donc elle ne sont jamais totalement détruites en mémoire.
    J'arrive tout de même a libérer quelques ressources, après avoir repris tout le code, changé toutes les méthodes de traitement sur des listes, des vecteurs, ( il y avais des références vraiment PARTOUT ), et du coup des OutOfMemory a tous vas quand on es un peu gourmand avec l'appli ..

    N'y a-t'il pas moyen de déréférencer totalement une frame ??
    Un objet ca j'y arrive, mais la JFrame a tout un tas de références sur les RootPanes, listeners etc, et je n'arrive pas a la vider totalement de la mémoire ..

    Je remercirai donc toutes reponses aux personnes qui rebondirait a mon post.

  2. #2
    Membre Expert
    Avatar de natha
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    2 346
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Janvier 2006
    Messages : 2 346
    Par défaut
    Salut,

    Effectivement c'est un problème, on ne parle pas assez de la libération mémoire et je l'ai également appris à mes dépends.
    Ce qui m'a permis d'en tirer plusieurs règles :

    - éviter les variables statiques d'objets
    - limiter l'utilisation des listeners
    - "cleaner" ses objets quand ils offrent une méthode le permettant (JDateChooser#cleanup(), Model#release(), etc.); supprimer les listeners lors d'une fermeture lorsque ceux-ci peuvent empêcher la bonne libération des ressources
    - utiliser des WeakReference<T> quand celà peut être une bonne idée ou quand ça s'avère nécessaire
    - catcher les RuntimeException

    Pas facile de détecter les problèmes quand il y en a un. En général je procède par élimination en réduisant l'écran au minimum puis en rajoutant/testant chaque élément afin d'identifier celui qui pose problème.

    L'autre solution c'est de ne jamais "fermer" ses écrans mais de les réutiliser autant que possible (ce que nous ne faisons pas, ou peut-être dans maxi 5% des cas car nous avons besoin de libérer la mémoire des écrans non utilisés).

    Bon courage

  3. #3
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Mars 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2008
    Messages : 23
    Par défaut re pb memoire
    Merci natha pour ta réponse
    Oui je me suis pas mal penché sur le problème du coup , et j'ai fait un pe plus de recherches.
    Merci pour tes conseils c'est déja ce que j'essaye de faire .. mais reprendre un projet qui es déja passé dans plusieurs mains, contenant 200 classes environ .. c'est pas facile d'optimiser l'utilisation mémoire ..
    Ce que je n'arrive pas à comprendre, après utilisation du profiler d'eclipse, quand j'ouvre une JFrame à partir d'une première JFrame, la seconde n'est jamais détruite .. il reste toujours une référence dessus ..
    j'ai beau faire des dispose, finalize, la mettre a null dans le parent .. elle n'est apparement pas détruite par le gc .. Bon pour une simple Frame qui fait qq octets ce n'est pas méchant, mais sur mon projets elle accumulent trop de données ..
    Pour le problème que je viens d'évoquer aurai-tu un autre conseil a me donner ?
    Merci de ta reponse en tout cas, bonne soirée

  4. #4
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 901
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 901
    Billets dans le blog
    54
    Par défaut
    Il y a 9 ans quand j'etais a la fac et que nous somme passe lors de la derniee annee du C/C++ au Java c'est clairement devenu d'un coup "casse pas la tete, laisse le GC bosser pour toi" (et je parle bien des profs, pas uniquement des etudiants). Hors une fois sorti du carquant de la fac, il est apparu clairement que les OutOufMemoryException se multiplient a vitesse grand V et qu'il a donc fallu apprendre un peu sur le tas comment limiter tout ca. Et ce n'est pas non-plus du cote des didacticiels et documentations officielles qu'on va forcement trouver des infos ou des indications de bonne pratique. De meme, aucun des livres "serieux" que j'ai ne s'attardent sur le sujet.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  5. #5
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Mars 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2008
    Messages : 23
    Par défaut RE pb memoire
    Citation Envoyé par bouye Voir le message
    (et je parle bien des profs, pas uniquement des etudiants).
    Ben oui voila j'ai exactement le même soucis en ce moment, et j'ai l'impression de tout réapprendre depuis que je fais des recherches sur le sujet ^_^
    Disons que les methodes d'apprentissages ne sont pas assez poussée sur le fonctionnement de la JVM je pense, sinon il aurait été plus clair que la gestion des références faisais tout de même parti du lot !!!

  6. #6
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Mars 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2008
    Messages : 23
    Par défaut Re PB Memoire
    Voila un exemple tout bete, mais dont j'aimerai avoir votre avis.
    Voila donc l'ouverture d'une Frame a partir d'une premiere, je n'ai pas mis de listener sur la 2nd Frame, et pourtant elle ne veux absolument pas se supprimer ...

    3 classes :

    1ere classe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    package monPak;
     
    public class Main {
     
        public static void main( String[] args )
        {
            PremFrame maframe = new PremFrame();
            maframe.setVisible(true);
        }
    }
    2eme classe
    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
    28
    29
    30
    31
    32
     
    package monPak;
     
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JButton;
    import javax.swing.JFrame;
     
    public class PremFrame extends JFrame {
     
        private static SecFrame secFrame;
        PremFrame parent = null;
        public PremFrame(){
            setTitle("PremFrame");
            setSize(200,200);
            setVisible(true);
            JButton bout = new JButton();
            bout.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent e) {
                    secFrame = new SecFrame(parent);
                }
            });
            this.getContentPane().add(bout);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            parent = this;
        }
     
        public void fermerSecFrame(){
            secFrame = null;
     
        }
    }

    3eme Classe
    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
    28
    29
    30
    31
    32
    33
     
    package monPak;
     
    import javax.swing.JFrame;
     
    public class SecFrame extends JFrame {
        PremFrame parent = null;
     
        public SecFrame(PremFrame parent) {
            this.parent = parent;
            super.setTitle("2ndFrame");
            super.setSize(200,200);
            super.setVisible(true);
            this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        }
     
        public void dispose() {
            parent.fermerSecFrame();
            parent=null;
            System.out.println("2ndFrame se dispose");
            super.dispose();
        }
     
     
        public void finalize(){
            System.out.println("2ndFrame se finalize");
            try {
                super.finalize();
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    }
    Le profiler me donne comme resultat apres avoir fermé la seconde frame :

    Memory Statistics - monPak.Main at Div-proj-b2-3-1 [ PID: 2972 ]
    >Package Total Instances Live Instances Collected Total Size (bytes) Active Size (bytes)
    [-] monPak 3 3 0 688 688
    PremFrame 1 1 0 336 336
    PremFrame$1 1 1 0 16 16
    SecFrame 1 1 0 336 336


    On voit qu'il y a toujours une live instance sur la secFrame, et sur l'Object References Table :SecFrame Is referenced by 75 object !!!!!!!!!!!!!!!!


    Object References Table - monPak.Main at Div-proj-b2-3-1 [ PID: 2972 ] (Filter: New_filter ) >Show Reference By Package Size (bytes) Number of References Details
    [-] PremFrame monPak 336
    [+] PremFrame monPak 336 Is referenced by 60 object(s).
    [+] PremFrame$1 monPak 16
    [-] SecFrame monPak 336
    [-] SecFrame monPak 336 Is referenced by 75 object(s).
    DefaultKeyboardFocusManager$DefaultKeyboardFocusManagerSentEvent monPak 200 Has 5 references to SecFrame.
    DefaultKeyboardFocusManager$TypeAheadMarker monPak 48 Has 2 references to SecFrame.
    Finalizer monPak 32 Has 1 references to SecFrame.
    FocusEvent monPak 384 Has 12 references to SecFrame.
    [+] InputMethodContext monPak 64 Is referenced by 2 object(s). Has 1 references to SecFrame.
    [+] JRootPane monPak 376 Is referenced by 2 object(s). Has 1 references to SecFrame.
    KeyboardFocusManager monPak 0 Has 1 references to SecFrame.
    KeyboardFocusManager$HeavyweightFocusRequest monPak 32 Has 2 references to SecFrame.
    KeyboardFocusManager$LightweightFocusRequest monPak 32 Has 2 references to SecFrame.
    [+] LightweightDispatcher monPak 40 Is referenced by 2 object(s). Has 1 references to SecFrame.
    MouseEvent monPak 840 Has 15 references to SecFrame.
    PaintEvent monPak 64 Has 2 references to SecFrame.
    PropertyChangeEvent monPak 32 Has 1 references to SecFrame.
    SequencedEvent monPak 320 Has 8 references to SecFrame.
    WeakHashMap$Entry monPak 40 Has 1 references to SecFrame.
    [-] WeakReference monPak 120 Is referenced by 2 object(s). Has 5 references to SecFrame.
    [+] PremFrame java.lang.ref 336 Is referenced by 60 object(s). Has 1 references to WeakReference.
    [+] SecFrame java.lang.ref 336 Is referenced by 75 object(s). Has 1 references to WeakReference.
    [+] WFramePeer monPak 96 Is referenced by 2 object(s). Has 1 references to SecFrame.
    WindowEvent monPak 480 Has 12 references to SecFrame.
    WInputMethod monPak 80 Has 2 references to SecFrame.

  7. #7
    Membre Expert
    Avatar de natha
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    2 346
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Janvier 2006
    Messages : 2 346
    Par défaut
    Citation Envoyé par couffi Voir le message
    Pour le problème que je viens d'évoquer aurai-tu un autre conseil a me donner ?
    Elle est sûrement liée à cause d'un listener que tu mettrais sur un objet de la frame parente. Pour que cette 2nde JFrame se libère correctement, elle ne doit pas avoir de lien fort avec un quelconque élément de la frame parente.
    Procède par élimination comme je l'ai suggéré dans mon premier post. Rajoute les portions de code au fur et à mesure tant que la frame se libère bien.

  8. #8
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Mars 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2008
    Messages : 23
    Par défaut Re pb memoire
    Merci natha je vais essayer ca, j'ai pourtant chercher un peut partout, sur des tutos, sur des exemples .. et je ne vois pas ce qu'il vas pas ..
    Le seul listener que j'ai sur la Frame c'est celui qui capture la fermeture de la fenetre, qui es censé la disposer et la finalizer .. Je la met a null dans la frame parent, elle n'as plus de références sur la Frame parente, mais dans le profiler j'ai toujours la "live instance" sur la frame enfant ..
    Bon sur mon projet j'ai des références un peut partout, donc je comprend qu'elle reste référencée qqpart .. mais pour une Frame vide .. la je comprend plus rien lol ..

    Enfin bon quelque part ces petit soucis ont bien mis en évidence le manque d'information sur la libération des objet a réaliser soit même si on veut que tout soit disopsé correctement.. J'ai évoqué le problème autour de moi avec mes collègues avant de poser la question ici, et eux non plus n'avais pas connaissances de tel soucis .. Disons qu'on a tous été un peut naif sur l'utilisation du GC ^_^
    Bonne journée

  9. #9
    Rédacteur
    Avatar de eclesia
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    2 110
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 110
    Par défaut
    Citation Envoyé par natha Voir le message
    - éviter les variables statiques d'objets
    ...
    - catcher les RuntimeException
    Je ne suis pas d'accord avec ses deux la.
    - L'utilisation des variables static fournit des objects qui vont etre réutilisé souvent, Il preferable d'avoir un object constant pour tout le monde que N instance d'objet. Bien sur il ne faut pas en abuser. mais ce n'est pas une mauvaise pratique en soi.

    - Si on en vient a catcher les runtime exceptions c'est qu'il a de gros soucis avec le fonctionnement de l'application, ca ressemble plus a un patch de derniere minute qu'une vrai pratique. La question que je me pose aussi, c'est "Ou peux tu bien utiliser ce catch efficacement ?". Le faire au moment d'une methode qu'on sait volumineux en cout memoire ? c'est inutile, la methode pourrais tres bien marcher et faire un OutOfMemory si une toute petite methode qui suit.

    Je rajoute quelques conseil :
    - Utiliser des classes immutables. ces classes peuvent etre utilisé beaucoup plus souvent qu'on ne le pense et permet d'avoir des objets dont le comportement et parfaitement previsible et donc simplifi grandement les divers soucis qu'on peut se faire avec la gestion memoire.
    - Essayer d'utiliser d'avantage les fabrique/service, ces objets sont generalement des singletons thread safe qui on un cout memoire permanent mais faible comparé a la creation de N instances.
    - Eviter de creer des objets inutiles pour les methodes.
    Par exemple vous avez une liste et vous voulez la remplir avec d'autres listes venant d'autres objects.
    Plutot que d'avoir une methode :
    utilisez plutot une methode du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void fillTrucs(List<Truc> malist);
    L'objet voit qu'on lui fournit une liste a remplir, il n'aura pas besoin d'en créé une.
    L'idéale est d'avoir ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    List<Truc> getTrucs(List<Truc> maList);
    L'objet créera une list si on passe une liste null, sinon il remplira celle fournie.
    Il y a plein de petite choses du genre qui permettent de grapiller pas mal d'espace memoire et enormement de performances.

  10. #10
    Membre du Club
    Inscrit en
    Juillet 2006
    Messages
    10
    Détails du profil
    Informations forums :
    Inscription : Juillet 2006
    Messages : 10
    Par défaut
    - L'utilisation des variables static fournit des objects qui vont etre réutilisé souvent
    C'est justement parceque rien ne le garantie que je disais qu'elles sont à éviter.
    Si l'on est sûr à 100% que l'objet référencé en static sera de longue durée de vie, pas de soucis, mais il faut éviter d'utiliser des variables static sans être sûr de la durée de vie des objets qu'elles référenceront.

    Concernant l'utilisation de singlethon plutôt que l'instantiation de plusieurs objets, je ne vois pas où est le problème, ou du moins, c'est hors-sujet si l'on parle des FUITES mémoire.
    Du moment que les objets sont de courte durée de vie, et qu'une fois inutilisés ils sont correctement collectés, celà ne pose pas de problème d'espace mémoire que d'en créer massivement (même si ça n'est peut être pas le plus optimisé, mais d'un point de vue 'FUITE MEMOIRE' ça ne pose aucun soucis).
    La question est justement, comment s'assurer que nos objets soient correctement collectés, qu'elles sont les bonnes pratiques à avoir.
    Je n'ai pas le sentiment d'avoir reçu de réponse satisfaisante (claire, exhaustive, fiable) pour l'instant.

  11. #11
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    Citation Envoyé par eclesia Voir le message
    - Eviter de creer des objets inutiles pour les methodes.
    Par exemple vous avez une liste et vous voulez la remplir avec d'autres listes venant d'autres objects.
    Plutot que d'avoir une methode :
    utilisez plutot une methode du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void fillTrucs(List<Truc> malist);
    L'objet voit qu'on lui fournit une liste a remplir, il n'aura pas besoin d'en créé une.
    L'idéale est d'avoir ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    List<Truc> getTrucs(List<Truc> maList);
    L'objet créera une list si on passe une liste null, sinon il remplira celle fournie.
    Autant je suis d'accord sur éviter des créer de gros objets inutiles, autant je ne suis pas d'accord avec ton exemple . Il comporte à mon sens plusieurs problèmes:

    1) Notation non 'javabean', ce qui implique que la méthode sera inutilisable dans des contexte type Expression Language (entre autres)
    2) non intuitif (on a tendance à rechercher dans l'api un getter , pas un filler), mais çà c'est une question de convention sur le projet j'imagine aussi
    3) aucun gain en instantiation. Ce que tu gagne en ne faisant pas un new ArrayList(taille), tu le perd sur le redimensionnement d'array que fait une arraylist lorsque sont tableau est plein.
    4) Une ArrayList occupe peu de mémoire par rapport à la mémoire qu'occupe les objets qu'elle contient.

  12. #12
    Rédacteur
    Avatar de eclesia
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    2 110
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 110
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    Autant je suis d'accord sur éviter des créer de gros objets inutiles, autant je ne suis pas d'accord avec ton exemple . Il comporte à mon sens plusieurs problèmes:

    1) Notation non 'javabean', ce qui implique que la méthode sera inutilisable dans des contexte type Expression Language (entre autres)
    2) non intuitif (on a tendance à rechercher dans l'api un getter , pas un filler), mais çà c'est une question de convention sur le projet j'imagine aussi
    3) aucun gain en instantiation. Ce que tu gagne en ne faisant pas un new ArrayList(taille), tu le perd sur le redimensionnement d'array que fait une arraylist lorsque sont tableau est plein.
    4) Une ArrayList occupe peu de mémoire par rapport à la mémoire qu'occupe les objets qu'elle contient.
    1) Il n'y a aucune obligation d'etre 100% javaBean... si un get/set ne se prete pas a le methode que l'on veut avoir, alors je ne vais pas me forcer a en mettre un get.
    2) la javadoc est la pour ca.
    3) Si son tableau n'est pas plein ou si des valeurs sont deja presente on y gagne.
    4) peut etre peu de memoire, mais un peu de memoire quand meme.

    C'est vrai que le "fillTruc" on le voit jamais (c'etait juste a titre d'exemple).
    On peut trouver beaucoup d'exemple dans les classes Java2D et autre relative au math.
    Exemple : AffineTransform
    Methode :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst) 
              Inverse transforms the specified ptSrc and stores the result in ptDst.
    Ce que je voulais dire dans tout ca, c'est qu'il y beaucoup de facon de reduire le nombres de references qui se baladent. Moins de references c'est moins de boulot pour le GC, moins de risques de fuite memoire et tres souvent un gain en performance.

Discussions similaires

  1. [Coup de gueule] Appel à la modération.
    Par r0d dans le forum Politique
    Réponses: 74
    Dernier message: 18/07/2006, 15h18
  2. Réponses: 1
    Dernier message: 31/05/2006, 11h27

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