Probléme de gros fichiers
Résolu
smater
Messages postés
17
Date d'inscription
Statut
Membre
Dernière intervention
-
smater -
smater -
Bonjour,
Je suis débutant JAVA,j'utilise Eclipse avec un serveur tomcat qui pour faire tourner mon programme qui récupère un fichier .csv et le remonte dans une base de données ligne par ligne, mon problème est dans la RAM, je met un Max Memory Pool en 1200m (c'est le maximum que je peux faire) sur tomcat, mais malheureusement, la RAM s'épuise dans l'exécution en me renvoyant l'erreur suivante:
java.lang.OutOfMemoryError: Java heap space on JSP.
Je ne sais pas quoi faire pour diminuer au moins cette consommation rapide en mémoire vu que le fichier .csv à remonter contient 600000 lignes, et je n'arrive à remonter que 236000 lignes. Le pire c'est que j'ai d'autres fichiers contenant des million de lignes à remonter aussi...
Merci d'avance pour Votre Aide...
Je suis débutant JAVA,j'utilise Eclipse avec un serveur tomcat qui pour faire tourner mon programme qui récupère un fichier .csv et le remonte dans une base de données ligne par ligne, mon problème est dans la RAM, je met un Max Memory Pool en 1200m (c'est le maximum que je peux faire) sur tomcat, mais malheureusement, la RAM s'épuise dans l'exécution en me renvoyant l'erreur suivante:
java.lang.OutOfMemoryError: Java heap space on JSP.
Je ne sais pas quoi faire pour diminuer au moins cette consommation rapide en mémoire vu que le fichier .csv à remonter contient 600000 lignes, et je n'arrive à remonter que 236000 lignes. Le pire c'est que j'ai d'autres fichiers contenant des million de lignes à remonter aussi...
Merci d'avance pour Votre Aide...
A voir également:
- Probléme de gros fichiers
- Gros fichiers .com - Guide
- Explorateur de fichiers - Guide
- Renommer des fichiers en masse - Guide
- Fichiers epub - Guide
- Gestionnaire de fichiers - Télécharger - Gestion de fichiers
2 réponses
Bonjour KX,
recuperer.jsp est la jsp qui contient le code, elle est bien formée, ce message est fournit après un bon moment d'attente pendant le upload du fichier .csv dans la base de donnée, ce message d'erreur explique le problème de mémoire si vous l'avez remarqué dans l'exception suivante:
javax.servlet.ServletException: Java heap space .
NB : quand je fouille dans la base de donnée je ne trouve que 50000 lignes ajoutées, alors que sa dois être tous le fichier qui contient 600000.
recuperer.jsp est la jsp qui contient le code, elle est bien formée, ce message est fournit après un bon moment d'attente pendant le upload du fichier .csv dans la base de donnée, ce message d'erreur explique le problème de mémoire si vous l'avez remarqué dans l'exception suivante:
javax.servlet.ServletException: Java heap space .
NB : quand je fouille dans la base de donnée je ne trouve que 50000 lignes ajoutées, alors que sa dois être tous le fichier qui contient 600000.
De toute évidence tu gères mal la lecture de ton fichier, en le stockant en RAM.
Normalement pour ce genre d'opérations, tu ne devrais avoir qu'une seule ligne en mémoire, une fois lue elle ne te sers plus à rien et tu peux la libérer de la mémoire.
Formellement, tu devrais avoir une consommation mémoire en O(1), et là tu es en O(n).
Donc ça n'a rien à voir avec ton Memory Pool, c'est ton code qui flanche !
Normalement pour ce genre d'opérations, tu ne devrais avoir qu'une seule ligne en mémoire, une fois lue elle ne te sers plus à rien et tu peux la libérer de la mémoire.
Formellement, tu devrais avoir une consommation mémoire en O(1), et là tu es en O(n).
Donc ça n'a rien à voir avec ton Memory Pool, c'est ton code qui flanche !
le voila :
<%
String s,sa;
s= request.getParameter("fichier");
if (s==null){s="mlklm";}else{
if(s.contains(":")){
sa=s.replaceAll("\\\\", "\\\\\\\\");}
else {
sa="d:\\excelcsv\\"+s;
}
out.print("<font color=red>Enregistrement du fichier <U><strong>'"+sa+"'</strong></U> Terminé</font>");
try{
String val="";
Class.forName("com.mysql.jdbc.Driver");
String url="jdbc:mysql://localhost/excelcsv";
Connection con1=DriverManager.getConnection(url,"root","");
java.sql.PreparedStatement req = null;
BufferedReader br = new BufferedReader(new FileReader(sa));
String ligne = null;
int i=0;String[] v1;
i=0;
while ((ligne = br.readLine()) != null )
{
// Retourner la ligne dans un tableau
// ligne = ligne+";";
//String[] data = ligne.split(";");
// Afficher le contenu du tableau
v1=ligne.split(";");
//if ( v1[i+1].contains("mois")||v1[i+1]==""||v1[i+1]==null){}else{
// out.print(v1[i]+","+v1[i+1]);
//--------------------------------|Annee|----|Mois|----|Matricule|---|Rubrique|--|Section|----|--MT---|--
val="insert into test values ("+v1[i]+","+v1[i+1]+","+v1[i+2]+",'"+v1[i+3]+"',"+v1[i+4]+","+v1[i+5]+",'0')";
req = con1.prepareStatement(val);
req.executeUpdate();
//}
}
br.close();
con1.close();
}catch (Exception e) {
e.printStackTrace();
}}
%>
<%
String s,sa;
s= request.getParameter("fichier");
if (s==null){s="mlklm";}else{
if(s.contains(":")){
sa=s.replaceAll("\\\\", "\\\\\\\\");}
else {
sa="d:\\excelcsv\\"+s;
}
out.print("<font color=red>Enregistrement du fichier <U><strong>'"+sa+"'</strong></U> Terminé</font>");
try{
String val="";
Class.forName("com.mysql.jdbc.Driver");
String url="jdbc:mysql://localhost/excelcsv";
Connection con1=DriverManager.getConnection(url,"root","");
java.sql.PreparedStatement req = null;
BufferedReader br = new BufferedReader(new FileReader(sa));
String ligne = null;
int i=0;String[] v1;
i=0;
while ((ligne = br.readLine()) != null )
{
// Retourner la ligne dans un tableau
// ligne = ligne+";";
//String[] data = ligne.split(";");
// Afficher le contenu du tableau
v1=ligne.split(";");
//if ( v1[i+1].contains("mois")||v1[i+1]==""||v1[i+1]==null){}else{
// out.print(v1[i]+","+v1[i+1]);
//--------------------------------|Annee|----|Mois|----|Matricule|---|Rubrique|--|Section|----|--MT---|--
val="insert into test values ("+v1[i]+","+v1[i+1]+","+v1[i+2]+",'"+v1[i+3]+"',"+v1[i+4]+","+v1[i+5]+",'0')";
req = con1.prepareStatement(val);
req.executeUpdate();
//}
}
br.close();
con1.close();
}catch (Exception e) {
e.printStackTrace();
}}
%>
Vu ton code, je pencherais pour un dépassement mémoire lié au BufferedReader.
Remarque :
À chaque fois que tu fais une concaténation de String avec un "+" tu créés un nouvel objet String, donc quand tu fais tes concaténations à rallonge avec tes v[i] ça devient assez coûteux en nombre d'objets créés.
Essayes avec cette modification :
Remarque :
À chaque fois que tu fais une concaténation de String avec un "+" tu créés un nouvel objet String, donc quand tu fais tes concaténations à rallonge avec tes v[i] ça devient assez coûteux en nombre d'objets créés.
Essayes avec cette modification :
Scanner sc = new Scanner(new File(sa)); while (sc.hasNextLine()) { String[] v1=sc.nextLine().split(";"); String val=String.format("insert into test values (%s,%s,%s,'%s',%s,%s,'0')",v1[0],v1[1],v1[2],v1[3],v1[4],v1[5]); con1.prepareStatement(val).executeUpdate(); } sc.close();
Malheureusement ça ne marche toujours pas, voila le code que j'ai contenant votre proposition:
<%
String s,sa;
s= request.getParameter("fichier");
if (s==null){s="mlklm";}else{
if(s.contains(":")){
sa=s.replaceAll("\\\\", "\\\\\\\\");}
else {
sa="d:\\excelcsv\\"+s;
}
out.print("<font color=red>Enregistrement du fichier <U><strong>'"+sa+"'</strong></U> Terminé</font>");
try{
Class.forName("com.mysql.jdbc.Driver");
String url="jdbc:mysql://localhost/excelcsv";
Connection con1=DriverManager.getConnection(url,"root","");
java.sql.PreparedStatement req = null;
//BufferedReader br = new BufferedReader(new FileReader(sa));
//String ligne = null;
int i=0;
i=0;
/*
while ((ligne = br.readLine()) != null )
{
v1=ligne.split(";");
// out.print(v1[i]+","+v1[i+1]);
//--------------------------------|Annee|----|Mois|----|Matricule|---|Rubrique|--|Section|----|--MT---|--
val="insert into test values ("+v1[i]+","+v1[i+1]+","+v1[i+2]+",'"+v1[i+3]+"',"+v1[i+4]+","+v1[i+5]+",'0')";
req = con1.prepareStatement(val);
req.executeUpdate();
//}
}*/
Scanner sc = new Scanner(new File(sa));
while (sc.hasNextLine())
{
String[] v1=sc.nextLine().split(";");
String val=String.format("insert into test values (%s,%s,%s,'%s',%s,%s,'0')",v1[0],v1[1],v1[2],v1[3],v1[4],v1[5]);
con1.prepareStatement(val).executeUpdate();
}
sc.close();
//br.close();
con1.close();
}catch (Exception e) {
e.printStackTrace();
}}
%>
<%
String s,sa;
s= request.getParameter("fichier");
if (s==null){s="mlklm";}else{
if(s.contains(":")){
sa=s.replaceAll("\\\\", "\\\\\\\\");}
else {
sa="d:\\excelcsv\\"+s;
}
out.print("<font color=red>Enregistrement du fichier <U><strong>'"+sa+"'</strong></U> Terminé</font>");
try{
Class.forName("com.mysql.jdbc.Driver");
String url="jdbc:mysql://localhost/excelcsv";
Connection con1=DriverManager.getConnection(url,"root","");
java.sql.PreparedStatement req = null;
//BufferedReader br = new BufferedReader(new FileReader(sa));
//String ligne = null;
int i=0;
i=0;
/*
while ((ligne = br.readLine()) != null )
{
v1=ligne.split(";");
// out.print(v1[i]+","+v1[i+1]);
//--------------------------------|Annee|----|Mois|----|Matricule|---|Rubrique|--|Section|----|--MT---|--
val="insert into test values ("+v1[i]+","+v1[i+1]+","+v1[i+2]+",'"+v1[i+3]+"',"+v1[i+4]+","+v1[i+5]+",'0')";
req = con1.prepareStatement(val);
req.executeUpdate();
//}
}*/
Scanner sc = new Scanner(new File(sa));
while (sc.hasNextLine())
{
String[] v1=sc.nextLine().split(";");
String val=String.format("insert into test values (%s,%s,%s,'%s',%s,%s,'0')",v1[0],v1[1],v1[2],v1[3],v1[4],v1[5]);
con1.prepareStatement(val).executeUpdate();
}
sc.close();
//br.close();
con1.close();
}catch (Exception e) {
e.printStackTrace();
}}
%>
Je pense que c'est split(";") qui pourrait provoquer cette erreur, ce qui signifierai que la "ligne" auquel elle est appliquée serait beaucoup plus grande que prévu, et que le tableau renvoyé contiendrait plus de cases que la mémoire ne peux en supporter ! C'est donc pour ça que je demandais si le fichier CSV était bien formé, c'est à dire, est-ce qu'il n'aurait pas à un moment une ligne de taille très élevée ?
De plus, j'aimerais bien savoir à quoi correspondent les deux lignes de codes 287 et 329, mentionnées dans la trace d'erreur...
PS. Il faudra peut-être changer System.err par un autre flux selon la manière dont tu débogues ta JSP.
50501 2011;10;56757;RGRKYYJ;1900;43534535.45
6 insert into test values (2011,10,56757,'RGRKYYJ',1900,43534535.45,'0')
1
50502 2011;11;56567;GRFGHIU;1200;5354.34532
6 insert into test values (2011,11,56567,'GRFGHIU',1200,5354.34532,'0')
java.sql.SQLException: java.lang.OutOfMemoryError: Java heap space
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1056)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:430)
at com.mysql.jdbc.PreparedStatement.getInstance(PreparedStatement.java:556)
at com.mysql.jdbc.ConnectionImpl.clientPrepareStatement(ConnectionImpl.java:1387)
at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4105)
at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4004)
at org.apache.jsp.recuperer_jsp._jspService(recuperer_jsp.java:300)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:97)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:332)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:314)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:264)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
at java.lang.Thread.run(Unknown Source)
Avant on était sur des javax.servlet.ServletException, alors que là on est sur du java.sql.SQLException.
Alors certes, dans les deux cas c'est de l'OutOfMemoryError, mais du coup on peux exclure le problème de split dont je parlais tout à l'heure... et s'intéresser d'un peu plus près au SQL.
Alors je n'y pas grand chose en BDD, mais voici deux questions que je me pose :
1) Est-ce que les Statement ne devraient pas être fermées ?
2) Est il indispensable de créer un PreparedStatement à chaque itération ?