Probléme de gros fichiers

Résolu
smater Messages postés 17 Date d'inscription   Statut Membre Dernière intervention   -  
 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...
A voir également:

2 réponses

smater
 
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.
2
KX Messages postés 16761 Date d'inscription   Statut Modérateur Dernière intervention   3 020
 
En fait c'est la ligne du dessous qui m'intrigue : Arrays.copyOfRange

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...
0
smater
 
pour le fichier CSV il est bien formé, je viens de le revérifié. pour les ligne 287 et 329 je ne sais pas ou vais-je les trouvé puisque ma jsp ne contient que 185 ligne en tous et le code de la JSP est le même que je vous ai envoyé il n' y a rien après
0
KX Messages postés 16761 Date d'inscription   Statut Modérateur Dernière intervention   3 020
 
Avec l'affichage supplémentaire que j'ai indiqué, qu'est-ce que ça donne sur les dernières itérations avant que ça plante ?

PS. Il faudra peut-être changer System.err par un autre flux selon la manière dont tu débogues ta JSP.
0
smater
 
Voila les deux dernière ligne de l'insertion avec débogage il s'est arrêté à la ligne 50501:

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)
0
KX Messages postés 16761 Date d'inscription   Statut Modérateur Dernière intervention   3 020
 
Là ce n'est plus la même erreur qui apparaît !
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 ?

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]);
	
	PreparedStatement req = con1.prepareStatement(val);
	req.executeUpdate();
	req.close();
}

sc.close();

2) Est il indispensable de créer un PreparedStatement à chaque itération ?

Scanner sc = new Scanner(new File(sa));
Statement req = con1.createStatement();

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]);
	req.executeUpdate(val);
}

req.close();
sc.close();
0
KX Messages postés 16761 Date d'inscription   Statut Modérateur Dernière intervention   3 020
 
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 !
1
smater
 
Vous avez tout à fait raison, je cherche maintenant une partie de code à ajouté lors de l'écriture pour vider la mémoire après chaque INSERT, si vous avez une idée ou des indication vous me les précisez... merci beaucoup pour votre aide
0
KX Messages postés 16761 Date d'inscription   Statut Modérateur Dernière intervention   3 020
 
Ce serait plus facile en donnant le bout de code correspondant (accès au fichier, et boucle d'insertion, et plus si c'est utile)
0
smater
 
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();
}}

%>
0
KX Messages postés 16761 Date d'inscription   Statut Modérateur Dernière intervention   3 020
 
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 :

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();
0
smater
 
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();
}}

%>
0