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

Java Discussion :

[Perf]java.lang.OutOfMemoryError - liste trop grande


Sujet :

Java

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 169
    Points : 113
    Points
    113
    Par défaut [Perf]java.lang.OutOfMemoryError - liste trop grande
    Salut à tous !

    Bon alors voilà, je vais vous expliquer mon problème.
    Je ne suis pas un pro de la programmation, mais je me débrouille ..... je fais du java depuis 2 ans en université (pour que vous voyez un peu mon niveau ... correct, mais sans plus).

    Actuellement, je fais une application, qui doit lire et analyser un fichier.

    je lis chaque ligne d'un fichier, je la découpe, et je met toutes les données qui m'interesse dans une objet. Cet objet a une dixaine de champs, à peu près.

    chaque objet créé, je le met dans une liste (java.util.list), afin de stocker ces données en mémoire, afin de les afficher ultérieurement.

    Alors chaque du fichier va donner un objet. Ca se passe très bien pour des petits fichiers, de l'ordre quelques mégas. Mais lorsque je dois analyser un fichier plus gros (dès 10 ou 15 Mégas) alors j'ai une erreur de type java.lang.OutOfMemoryError qui se lance.

    Alors c'est que ma liste devient trop grande.

    ça bloque à 10 Mégas, alors que certains fichiers dépasseront les 100Mégas.

    Mon problème, c'est qu'à mon niveau, rien ne me permet de contourner ce genre de problème .... je conçoit que c'est un problème de conception.... ma structure n'est pas bonne, enfin des trucs comme ça ..... que me conseillez vous de faire ? Avez vous déjà été confronté à ce genre de problème, et qu'avez vous fait ?

    Merci !



    [Modéré par Didier] : ajout de tag dans le titre - Les règles du forum Java

  2. #2
    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,

    Tu n'utiliserais pas des cancaténations de String avec + dans des boucles ???
    Si c'est le cas utilises des StringBuffer !!!

    Enfin si tes fichiers sont vraiment gros tu devras utiliser les paramètres -Xms et -Xmx de java pour augmenter la mémoire allouée à la JVM...

    a++

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 169
    Points : 113
    Points
    113
    Par défaut
    merci du tuyau pour le -xms et xmx.
    Mais comment utiliser ces parametres ? à la compilation ?
    j'utilise Eclipse, et je fais eune application Struts avec le pluggin Exadel.

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    760
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 760
    Points : 626
    Points
    626
    Par défaut
    java est la commande pour lancer ton programme depuis un terminal, j'imagine que puisque eclipse de permet de lancer ton programme, cet EDI doit aussi te permettre de regler les options. Neanmoins ce domaine la concerne exclusivement Eclipse (pour plus de reponse >> forum eclipse...).

    Cette option se fait lors du lancement, donc apres la compilation.

    regarde ce post http://www.developpez.net/forums/viewtopic.php?t=84427
    PS : Dans le cadre du jdk 5.0 tu peux utiliser StringBuilder à la place de StringBuffer, mais StringBuilder n'est pas thread-safe. cf FAQ et API

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 169
    Points : 113
    Points
    113
    Par défaut
    Merci de ta réponse.
    En fait je lance mon application par une adresse dans internet explorer, vu que c'est une application Struts, avec le serveur de servlet Tomcat.

  6. #6
    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,

    Regarde dans la documentation de Tomcat pour cela...

    Mais je pense quand même que tu dois revoir ton code car si ca bloque à 10 Mo ca ne suffira pas d'augmenter la mémoire...

    a++

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 169
    Points : 113
    Points
    113
    Par défaut
    ben justement, je pense que c'est un problème de conception de programmation ... le fait de mettre un objet par ligne, et de ranger ces objets dans une liste ....... mais à part ça, je vois pas comment faire pour s'y prendre ...

  8. #8
    Membre habitué
    Profil pro
    Inscrit en
    Novembre 2002
    Messages
    154
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2002
    Messages : 154
    Points : 143
    Points
    143
    Par défaut
    Que veux tu faire de ces lignes? Est tu obliger de toutes les charger d'un seul coup?

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 169
    Points : 113
    Points
    113
    Par défaut
    en fait je balance mon objet java.util.list dans une page jsp (struts), et grâce au tag <layout:collection> je peux tout afficher, avec un certain nombre de ligne par page, etc ...
    avec ce tag, je n'ai pas à m'occuper de l'itération de la liste, il le fait tout seul.

  10. #10
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 169
    Points : 113
    Points
    113
    Par défaut
    En effet, j'ai pensé à l'idée de ne pas charger tout d'un coup, genre charger 100 lignes à chaque fois, que l'utilisateur chage de page.

    Mais je pense aux innombrables problèmes dont je serai incapable de résoudre, comme :

    - j'ai un bouton qui permet de trier toute la liste d'un coup. Mon patron insiste sur "TOUTE la liste d'un coup". Si la liste n'est pas harger entièrement en mémoire, comment la trier entièrement.

    - gérer les différentes pages, recommencer à lire dans le fichier à un endroit précis, ......

    enfin c'est vraimment au dessus de mon niveau pour l'instant.

  11. #11
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 169
    Points : 113
    Points
    113
    Par défaut
    en mettant le heap de la jvm à 512Mo (le maximum de ma machine de test) pour l'instant un fichier de 60Mo passe, mais faut encore que j'essaye avec 120Mo.

  12. #12
    NGY
    NGY est déconnecté
    Membre habitué
    Inscrit en
    Août 2002
    Messages
    137
    Détails du profil
    Informations forums :
    Inscription : Août 2002
    Messages : 137
    Points : 164
    Points
    164
    Par défaut
    Je pense que la méthode qui consiste à transformer une ligne en un objet est la bonne.
    En général, on découpe la lecture en plusieurs fois pour éviter le OutOfMemory.

    Citation Envoyé par laurent.c123
    (...) Mon patron insiste sur "TOUTE la liste d'un coup". (...)
    OK : Chaque chose a un coût. Pour lui, ce sera de la RAM !

    Plus sérieusement, es-tu sûr de ne jamais avoir un fichier plus gros que ce que tu peux traiter (genre 200 Mo) ?

    Et donne un peu de code, qu'on puisse voir s'il n'y a pas des optimisations à faire.

  13. #13
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 169
    Points : 113
    Points
    113
    Par défaut
    salut ngy !
    Ben là je bosse sur des fichiers de 4 Mo, donc il n'y avait pas de problème. Pour voir, mon patron m'a donné un fichier de 15 Mo, et bim !, ce qui devait arriver arriva, et c'est là que je me suis penché sur ce problème. Il m'a affirmer qu'il avait aussi des fichiers de 120Mo, il ne m'a pas parlé de fichiers de taille supérieure.

    Donc comme je le disais, j'ai augmenté la taille heap, que j'ai passé à 512Mo maximum, car c'est ma machine de test, 1 GHZ, un pauvre truc je vous dit même pas comme je me tire des balles quand je bosse sous eclipse ! Dès fois il rame pendant 10 minutes pour justedérouller un package .. enfin ....

    Donc dans cette config, un fichier de 60 Mo passe bien. Pour un fichier de 120 Mo, il rame pendant 10 minutes, puis il lance une erreur OutOfMemoryError. Avec plus de Ram, comme il y a sur le serveur (le vrai,pas ma daube) ça devrait passer, en augmentant encore légèrement la taille, mais bon, après imaginez, il faudrait un serveur entièrement dédié à mon application ! Mégalo, le mec ......

    Bon, comme tu me l'a demandé, ngy, je vous dévoile mon code ultra confidentiel et déjà super optimisé et méga rapide, enfin, voilà mon code de merde, quoi .... ( )!!
    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
     
    	public List parseLog(String nameLog, String compte, String enquete, List queryList) throws IOException{
     
    		BufferedReader in = null;
    		try {in = new BufferedReader(new FileReader(nameLog));} 
    		catch (IOException e) {throw new IOException("FichierNonTrouvé->"+nameLog);}
     
    		List theList = new LinkedList();
    		Structure struct;
    		String aLine;
    		StringTokenizer lineTokens;
     
    		String code="",dateHeure="",date="",heure="",ip="",account="",survey="",query="",ref="";
    		String page="",pages="",key="";
    		String compteEnquete="",requete="";
     
    		int ind1, ind2;
     
     
     
    		try{
     
    			while ((aLine = in.readLine()) != null) {
    				lineTokens=new StringTokenizer(aLine,"\t");
     
    				if (lineTokens.hasMoreTokens())code=lineTokens.nextToken();
    				if (lineTokens.hasMoreTokens())dateHeure=lineTokens.nextToken();
    				if (lineTokens.hasMoreTokens())ip=lineTokens.nextToken();
    				if (lineTokens.hasMoreTokens())compteEnquete=lineTokens.nextToken();
    				if (lineTokens.hasMoreTokens()) {
    					requete = lineTokens.nextToken();
    					try{
    						requete=URLDecoder.decode(requete,"UTF-8");
    					}catch(IllegalArgumentException e){}
    					ind1=requete.indexOf("query=");
     
    					if (ind1<0)continue;
     
    					//on cherche le parametre Query
    					ind2=requete.indexOf("&", ind1);
    					if(ind2<0)ind2=requete.length();
    					ind1=ind1+6;
     
    					query=requete.substring(ind1, ind2);
     
    					if(!queryList.contains(query))continue;
     
    					//on cherche le compte
    					ind1=1;
    					ind2=compteEnquete.indexOf("/", ind1);
    					if (ind1>-1 && ind2>0)account=compteEnquete.substring(ind1,ind2);
     
    					//on cherche l'enquete
    					ind1=compteEnquete.indexOf("/",ind2+1);
    					ind2=compteEnquete.indexOf(".",ind1);
    					if (ind1>-1 && ind2>0)survey=compteEnquete.substring(ind1+1,ind2);
     
    					if (  !((account.equals(compte) || compte.equals(""))
    							&&
    						    (survey.equals(enquete) || enquete.equals("")))
    						) continue;
     
     
    					struct=new Structure();
     
    					int indDH=dateHeure.indexOf(" ");
    					if(indDH>-1){
    						struct.date=dateHeure.substring(0,indDH);
    						struct.heure=dateHeure.substring(indDH,dateHeure.length());
    					}
     
    					struct.code=code; struct.ip=ip;
    					struct.compte=account; struct.enquete=survey; struct.query=query;
     
    					//on récupère le "ref"
    					ind1 = requete.indexOf("ref=");
     
    					if (ind1 > -1) {
    						ind2 = requete.indexOf("&", ind1);
    						if (ind2 < 0) ind2 = requete.length();
    						ind1=ind1+4;
     
    						struct.ref=requete.substring(ind1,ind2);
    					}
     
    					//on récupère le "page"
    					ind1 = requete.indexOf("page=");
     
    					if (ind1>-1) {
    						ind2=requete.indexOf("&", ind1);
    						if (ind2 < 0)ind2 = requete.length();
    						ind1 = ind1 + 5;
    						struct.page=requete.substring(ind1, ind2);
    					}
     
    					//on récupère le "pages"
    					ind1 = requete.indexOf("pages=");
     
    					if (ind1>-1) {
    						ind2=requete.indexOf("&", ind1);
    						if (ind2<0)ind2 = requete.length();
    						ind1 = ind1 + 6;
    						struct.pages=requete.substring(ind1,ind2);
     
    					}
     
    					//on récupère le "key"
    					ind1 = requete.indexOf("key=");
    					if (ind1 > -1) {
    						ind2 = requete.indexOf("&", ind1);
    						if (ind2 < 0)ind2 = requete.length();
    						ind1=ind1+4;
    						//else ind1=ind1+6;
    						//struct.key = URLDecoder.decode(requete.substring(ind1, ind2));
    						struct.key=requete.substring(ind1,ind2);
     
    					}
     
    					//on récupère les "vi"
    					ind1=requete.indexOf("&v");
    					if (ind1>-1) {
    						if (requete.charAt(ind1 + 2)>=48 && requete.charAt(ind1 + 2)<=57) {
    							ind2=requete.length();
    							if (ind2 > -1) {
    								StringBuffer sb=new StringBuffer(requete.substring(ind1+1,ind2));
    								int lastI=sb.lastIndexOf("&");
    								while (sb.length()>lastI+1 && sb.charAt(lastI+1)!='v') {
    									sb.delete(lastI, sb.length());
    									lastI = sb.lastIndexOf("&");
    								}
     
    								//////////////////////////////////////////////////////////
    								struct.variables=sb.toString();
    								requete=requete.replace(struct.variables,"");
    								struct.parametres=requete;
     
    								struct.variables = struct.variables.replace("&", "<br>");
    							}
    								//////////////////////////////////////////////////////////
     
    						}
    					}		
     
    					theList.add(struct);			
     
    				}
     
     
    			}//while ((aLine = in.readLine()) != null)
     
    		}//try
    		catch(IOException e){}
    		return theList;
    	}

  14. #14
    Membre actif
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    220
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 220
    Points : 266
    Points
    266
    Par défaut
    Une idee comme ca...

    Tu ne pourrais pas passer ton fichier dans une base de données ?
    A priori, tu n'aurais plus besoin de toute cette memoire, car tu aurais juste a faire une lecture dans ta table, et tu pourrais recuperer tes données facilement, triées comme tu veux, etc...

    A voir par contre pour le temps de chargement aussi...

    Remarque, avec un fichier de 120 Mo, ca te prendra quand meme du temps, surtout si tu le lis ligne par ligne...

  15. #15
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 169
    Points : 113
    Points
    113
    Par défaut
    Citation Envoyé par ghorgor
    Une idee comme ca...

    Tu ne pourrais pas passer ton fichier dans une base de données ?
    A priori, tu n'aurais plus besoin de toute cette memoire, car tu aurais juste a faire une lecture dans ta table, et tu pourrais recuperer tes données facilement, triées comme tu veux, etc...

    A voir par contre pour le temps de chargement aussi...

    Remarque, avec un fichier de 120 Mo, ca te prendra quand meme du temps, surtout si tu le lis ligne par ligne...
    ça peut être une idée de mettre ça dans une base de donnée, mais je pense que ce n'est pas à moi à faire ça. Mais c'est une idée à soumetre aux chefs (je ne suis que stagiaire).

    Effectivement, un fichier de 120Mo ça prend du temps de lire ligne par ligne. Sur mon pc de test, où je n'ai pas plus de 512Mo, il travaille 7 minutes sur le fichier de 120Mo avant de lancer une OutOfMemoryError.

  16. #16
    Membre actif
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    220
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 220
    Points : 266
    Points
    266
    Par défaut
    Si tu veux l'accelerer quand meme, fais une lecture par bloc de 5000 octets par exemple, et fais un decoupage sur les retour chariots/nouvelle ligne (\r\n), afin de retrouver tes lignes...

    Il faut cependant faire gaffe aux fins de lecture, ne se terminant pas par un \r\n...

    Les acces en lecture sont assez couteux, du coup, en limitant le nombre d'acces, tu risques d'accelerer considerablement ton traitement...

    J'ai fait une appli qui doit modifier des flux en EBCDIC de cette maniere, et je fais la lecture / ecriture d'un fichier de 250 Mo en 5 minutes...

    Maintenant, il est vrai que je ne conserve pas tout en memoire...

  17. #17
    NGY
    NGY est déconnecté
    Membre habitué
    Inscrit en
    Août 2002
    Messages
    137
    Détails du profil
    Informations forums :
    Inscription : Août 2002
    Messages : 137
    Points : 164
    Points
    164
    Par défaut
    Et ouic'est pas trop un problème de temps, mais plutôt de taille mémoire. D'ailleurs souvent, l'amélioration de l'un est aux dépends de l'autre.

    Bon en regardant (rapidement, j'ai pas beaucoup de temps !) ton code n'a pas l'air de trop "gaspiller" de mémoire, alors je ne sais pas trop.

    Par contre, essaie de mieux découper ton code. Tu devrais faire une méthode genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    private Struct ligneToStruct(String uneLigne) throws LesExceptionsQuiVontBien
    et tu l'appelles dans ta boucle
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      while ((aLine = in.readLine()) != null) {
        theList.add( ligneToStruct(aLine) );
      } //while ((aLine = in.readLine()) != null)
    Ce sera plus lisible et plus facile à maintenir.
    [Potentiellement n'importe quoi]Et ça jouera peut-être sur la mémoire (plus de variables locales, donc libération moins tardive).[/Potentiellement n'importe quoi]

  18. #18
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 169
    Points : 113
    Points
    113
    Par défaut
    Merci les gars, je vais prendre en compte tout ça !!

  19. #19
    Membre actif
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    220
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 220
    Points : 266
    Points
    266
    Par défaut
    J'adore tes balises persos NGY... Tres explicites... Sinon, je suis d'accord que c'est plutot un probleme de taille memoire, mais ca fait jamais de mal d'accelerer ses propres traitements... C'est pour ca que j'avais proposé de passer par une base de données avant...

  20. #20
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 169
    Points : 113
    Points
    113
    Par défaut
    Tout à fait d'accord avec toi ghorgor, j'ai apprécié ta démarche !

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 4
    Dernier message: 18/09/2006, 11h02
  2. Eclipse erreur : java.lang.OutOfMemoryError: Java heap space
    Par sderecourt dans le forum Eclipse Java
    Réponses: 1
    Dernier message: 14/04/2006, 12h28
  3. [webService][Axis] java.lang.OutOfMemoryError
    Par webspeak dans le forum Services Web
    Réponses: 8
    Dernier message: 25/04/2005, 18h58
  4. [Strategie]Pb de java.lang.OutOfMemoryError
    Par eaque dans le forum Général Java
    Réponses: 3
    Dernier message: 06/04/2005, 12h01
  5. [JSP] pb " java.lang.outOfMemoryError "
    Par lthomas dans le forum Servlets/JSP
    Réponses: 5
    Dernier message: 31/03/2005, 11h13

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