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

Langage Java Discussion :

Serveur qui prend trop de mémoire


Sujet :

Langage Java

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 16
    Points : 11
    Points
    11
    Par défaut Serveur qui prend trop de mémoire
    Bonjour,

    J'ai développé un petit serveur de tchat qui fonctionne bien, mais quia une facheuse tendance à bouffer de la ram avec le temps. Si bien qu'au bout d'une quinzaine de jours de lancement il est à 15% d'utilisation de la ram de mon serveur (1go de ram sur le serveur ...)

    J'ai beau regardé mon code je comprend pas trop d'où est ce ca peut provenir. Il doit surement y a un problème pour le que le garbage collector ne fasse pas son boulot.

    Je vous mets ici les grandes lignes du programme en espèrant que vous pourrez me guider sur quelques pistes pour faire baisser l'utilisation de la ram.


    Voilà la fonction principale du serveur qui ouvre un thread pour chaque client qui se connecte :

    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
        public static void main (String[] args){
            ServeurTchat serveur =  new ServeurTchat();
            Integer port = new Integer("xxxxx");
            if(args.length > 0 ){
                serveur.id_message_salle = new BigInteger(args[0]);
                serveur.id_message_partie = new BigInteger(args[0]);
            }
            ServerSocket ss = null;
            try{
                ss = new ServerSocket(port.intValue()); // ouverture d'un socket serveur sur port
                System.out.println("Serveur ServeurTchat démarré ...");
     
            }
            catch(IOException ioe){
                serveur.ecrire_log_erreur(serveur.message_erreurs[2] + ioe.getMessage());
            }
     
            while (true){
                //Ouverture thread client
                try{
                    new ServeurTchatThread(ss.accept(), serveur);
     
                }
                catch(IOException ioe){
                    ioe.printStackTrace();
                    serveur.ecrire_log_erreur(serveur.message_erreurs[5] + ioe.getMessage());
                }
            }
     
     
        }

    J'utilise plusieurs hashtables pour stocker les différents messages du tchat. En fait il y a un hashtable qui contient la liste des salles du tchat, et dans chaque salle un autre hashtable avec la liste des messages indéxés par un identifiant de type BigInteger.

    Les messages sont supprimés des différents hashtables toutes les 5 min.


    Donc à chaque connexion du client j'ouvre un Thread :

    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    public ServeurTchatThread(Socket so, ServeurTchat se) {
            socket = so;
            serveur = se;
            try{
                // fabrication d'une variable permettant l'utilisation du flux de sortie avec des string
                _out = new PrintWriter(so.getOutputStream());
                // fabrication d'une variable permettant l'utilisation du flux d'entrée avec des string
                _in = new BufferedReader(new InputStreamReader(so.getInputStream()));
            }
            catch (IOException e){ 
                serveur.ecrire_log_erreur(serveur.message_erreurs[1] + "{" + so.getInetAddress().getHostAddress()  + "}");
            }
     
            _t = new Thread(this); // instanciation du thread
            _t.start(); // demarrage du thread, la fonction run() est ici lancée
     
        }
     
        public void run(){
     
            //On récupère la commande du client :
            String messageClient = "";
            String tmp = "";
            try{
                while(! (tmp = _in.readLine()).equals("@finenvoi")){
                    messageClient += tmp;
                }
     
                //[...] Traitement [...]
     
     
                _out.write(print_result);
                _out.close();
     
     
     
            }
            catch(Exception ioe){
                ioe.printStackTrace();
            }
            finally{
                try{
                    _in.close();
                    _out.close();
                    socket.close();
                }
                catch(Exception e){
     
                }
     
            }
     
        }

    Je stocke donc les références du socket et du serveur dans le thread, peut être est ce pour ça que le garbage collector ne supprime pas la mémoire du thread , enfin ça serait un problème car j'ai besoin de ces références ...

    Ou peut être est ce mes hashtable qui prennent trop de mémoire, pourtant je n'ai pas vu de méthodes particuilères pour leur faire libérer de la mémoire. Je supprime mais libère t-il la mémoire ?

    Ou autre chose ?

    Bref je sèche complètement, alors peut etre auriez vous quelques pistes de réflexion ou conseils pour trouver d'ou peut provenir cette mémoire qui grime sans cesse ??

    Je suis en train de développer un autre serveur en java qui lui aura du traitement bien plus lourd que d'afficher des messages pour un tchat, alors j'ai bien peur qu'en lançant le deux en meme temps j'aurais presque toute la ram d'utilisée ... Donc il faudrait que je trouve une soluce (autre que d'acheter de la ram )

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Février 2006
    Messages
    238
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 238
    Points : 267
    Points
    267
    Par défaut
    Salut,

    Est-ce que ton serveur est stressé?
    Parceque s'il y a une forte charge d'utilisateur, cela peut s'expliquer, si il y à de nombreux channels avec de nombreux message, 15% de 1go ne représente pas beaucoup, par contre s'il n'y a que très peu de personnes, il faut vérifier que tu déréférence tous après chaque thread.
    Tu dois le savoir, mais le GC ne supprime un objet que lorsqu'il n'est plus du tout référencé.

    Voilà, a+

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 16
    Points : 11
    Points
    11
    Par défaut
    oui y a pas mal de monde sur le serveur, ca peut aller jusqu'à 80 connectés au maximum et en moyenne 40 à 50. Sachant que chaque utilisateur peut faire environ 2 à 3 requetes toutes les 5 secondes.

    Par contre la mémoire ne fait qu'augmenter meme quand il ya moins de monde. Donc j'ai l'impression qu'il ne libère jamais la mémoire. Dans les périodes creuses la mémoire devrait chuter mais ce n'est pas le cas.

    J'avais essayé de mettre à null les réfénces à la fin du thread dans la méthode run mais c'est encore pire au final.

  4. #4
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,


    Ta lecture des données peut poser problème si tu reçois une grosse quantité de données, car il faut éviter d'utiliser l'opérateur + dans une boucle...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    	String messageClient = "";
    	String tmp = "";
     
    	while(! (tmp = _in.readLine()).equals("@finenvoi")){
    		messageClient += tmp;
    	}
    A la place il faut utiliser un StringBuffer (voir un StringBuilder à partir de Java 5.0) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    	StringBuffer buffer = new StringBuffer();
    	String tmp = null;
     
    	while(! (tmp = _in.readLine()).equals("@finenvoi")){
    		buffer.append(tmp);
    	}
    	String messageClient = buffer.toString();

    Pour plus d'info voir la FAQ : Comment concatener des chaînes de caractères ?

    a++

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    548
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2006
    Messages : 548
    Points : 635
    Points
    635
    Par défaut
    Quand la JVM n'a plus assez de mémoire, elle fait passer le GC et parfois en même temps augmente la taille de sa mémoire. A ma connaissance, elle ne fait pas baisser la taille de la mémoire. Donc à mon avis ce comportement est normal : au cours de la vie du serveur, la taille augmente de temps en temps, ce qui permet d'éviter que le GC ne passe en permanence.

    Vu la façon dont tu fais des +=, tu consommes beaucoup d'objets temporaires, il est donc normal que la JVM alloue pour ça beaucoup de mémoire. Ca baissera surement en appliquant le conseil d'adiGuba

    Maintenant si tu suspectes qu'il y a une (des) fuite(s) mémoire, une solution pour le vérifier ça peut être de baisser la taille maximale (-Xmx64M par ex.) et de voir si tu reçois des OutOfMemoryError au bout de quelques temps.

Discussions similaires

  1. Process Apache qui utilise trop de mémoire
    Par charline_irlande dans le forum Apache
    Réponses: 2
    Dernier message: 26/10/2009, 18h29
  2. Une lecture de fichier midi qui consomme trop de mémoire
    Par padodanle51 dans le forum Général Java
    Réponses: 6
    Dernier message: 12/04/2008, 12h52
  3. Réponses: 3
    Dernier message: 21/01/2008, 15h38
  4. Application qui prend beaucoup de mémoire
    Par Khrysby dans le forum Général Dotnet
    Réponses: 6
    Dernier message: 09/10/2007, 23h44
  5. Problème de Thread qui prend trop de mémoire
    Par petozak dans le forum Général Java
    Réponses: 20
    Dernier message: 11/12/2006, 16h24

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