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

JDBC Java Discussion :

Grosse quantité de photo et mémoire


Sujet :

JDBC Java

  1. #1
    Nouveau membre du Club
    Inscrit en
    Avril 2009
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Avril 2009
    Messages : 48
    Points : 38
    Points
    38
    Par défaut Grosse quantité de photo et mémoire
    Bonjour,

    J'ai un problème avec un petit script et la mémoire. J'ai environ 4000 images (2000 de 20ko max et 2000 de 500 à 700ko) à mettre sur un serveur Mysql. A chaque fois que je le lance ça me rend une erreur comme quoi il manque de mémoire.

    Je comprends pas bien pourquoi la mémoire ne se décharge pas...

    Je met les 2 script si jamais quelqu'un à une idée :

    Première classe qui parcours le dossier source. Pour ce qui est de la méthode ChangeFileName.getNumberFromScreenshot() elle donne juste un int et fonctionne parfaitement.
    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
    package insertImage;
     
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.lang.management.ManagementFactory;
    import java.lang.management.MemoryMXBean;
    import java.sql.ResultSet;
    import java.sql.SQLException;
     
    import changeFileName.ChangeFileName;
     
    public class InsertImage {
    	static Mysql mysql = null;
    	public static void main(String[] args) throws SQLException, IOException {
    		mysql = new Mysql();
    		mysql.connectToMySQL("192.168.1.23", 3306, "root", "toor");
    		mysql.executeQuery("USE dolModel");
    		File dirSourceResized = new File("/home/charles/Images/resized");
    		File dirSourceNormal = new File("/home/charles/Images/final");
    		int i = 0;
    		MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
    		if (dirSourceResized.exists()) {
    			for (int j=0;j<3000;j++) {
    				newImage(j);
    			}
    			for (File screenShotNormal : dirSourceNormal.listFiles()) {
    				if (screenShotNormal.getName().contains("sshot")) {
    					i++;
    					insertNewImage(ChangeFileName.getNumberFromScreenshot(screenShotNormal), new File(dirSourceResized+File.separator+screenShotNormal.getName()) , screenShotNormal);
    				}
    			}
    		}
     
    	}
     
    	private static void newImage(int j) throws SQLException {
    		Mysql.newImage(j);
    	}
     
    	private static void insertNewImage(int numberScreen, File screenShotResized, File screenShot) throws SQLException, IOException {
    		Mysql.insertImage(numberScreen,screenShotResized, screenShot);
    	}
    }
    Je ne met que la méthode qui est utile en ce qui concerne la 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
        public static void insertImage(int id, File screenShotResized,File screenShot) throws SQLException, IOException {
     
        	BufferedInputStream screen = new BufferedInputStream(new FileInputStream(screenShot));
        	byte[] bytes = new byte[screen.available()];
     
     
        	BufferedInputStream screenResized = new BufferedInputStream(new FileInputStream(screenShotResized));
        	byte[] bytesMini = new byte[screenResized.available()];
     
        	screen.read(bytes);
        	screenResized.read(bytesMini);
     
        	stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
     
        	rsImage = stmt.executeQuery("select * from T_MODEL where idModel="+id);
        	rsImage.first();
     
        	rsImage.updateBytes("imageNormalModel", bytes);
        	rsImage.updateBytes("imageResizedModel", bytesMini);
     
        	rsImage.updateRow();
     
        	screen.close();
        	screenResized.close();
        }
    Je pense que le problème vient du fait que la mémoire n'est pas libéré quand la méthode insertImage() se termine. Du coup les images en mémoire (dans les variables bytes[] et bytesMini[]) prennent de la place et cette place monte à plus de 500Mo ce qui est pas bon du tout... Au bout d'un moment le script plante disant qu'il manque de mémoire.

    Si quelqu'un pouvait jeter un coup d'oeil pour m'expliquer.

    J'ai mis en fichiers attachés les 2 classes utiles. Pour la connexion j'utilise le connecteur qu'on peut trouver ici :
    http://dev.mysql.com/downloads/connector/j/5.1.html

    Merci d'avance.

    edit : C'est au fichier 656 que ça fou la merde (c'est pas toujours le même) la mémoire utilisé monte a 474Mo. L'erreur c'est java.lang.OutOfMemoryError : Java heap space à la ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    rsImage.updateBytes("imageNormalModel", bytes);
    Çà par contre ça change pas je crois (mais pas sûr...) Il est tard pas le temps de retester...
    Fichiers attachés Fichiers attachés

  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,



    Quelques remarques :

    • Quasiment toutes tes variables (même locales) sont en static.
      Elles sont donc conserver inutilement...
      Il n'y a aucune raison à cela !
    • Tu dois fermer explicitement toutes les ressources externes, qui ne sont pas managé par le GC (fichiers, sockets, mais surtout dans ton cas connection, statement et resultset). Ces ressources peuvent utiliser indirectement beaucoup de mémoire ! utilises des try/finally pour cela...
    • Méfie toi d'available() : ce dernier ne te donne pas forcément la taille du fichier. Tu devrais revoir ta méthode de lecture.
    • Tu utilises un select updatable pour faire un insert
    • Tu limites ton code à MySQL


    a++

  3. #3
    Nouveau membre du Club
    Inscrit en
    Avril 2009
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Avril 2009
    Messages : 48
    Points : 38
    Points
    38
    Par défaut
    Merci de ta réponse j'y ai un peu travaillé.

    J'ai réduis le nombre de variable static et fermé les statement et resultset plus souvent.

    Ca tourne encore et je suis à 1500 images. De temps en temps la mémoire monte jusqu'à 30Mo puis redescend à 9Mo.

    Je fournis les 2 fichiers modifiés si ça intéresse des gens...

    Sinon pour le fait que c'est limité à Mysql, c'est pas si grave car c'était juste un petit script comme ça. Le available fonctionne pour ma part.

    Sinon j'ai pas bien compris la remarque
    Tu utilises un select updatable pour faire un insert
    Tu pourrais m'indiquer de quelle ligne tu parle ?

    En tout cas merci, le problème principal venait je pense du fait que je fermais pas explicitement les resultset et statement. Je pensais que le GC s'en chargeait.

    Bye

  4. #4
    Nouveau membre du Club
    Inscrit en
    Avril 2009
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Avril 2009
    Messages : 48
    Points : 38
    Points
    38
    Par défaut
    et voila 2 367 enregistrements pour 841,1Mo et données, principalement photo.

    Merci beaucoup. Faut mettre résolus sur le post ?

  5. #5
    Nouveau membre du Club
    Inscrit en
    Avril 2009
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Avril 2009
    Messages : 48
    Points : 38
    Points
    38
    Par défaut
    J'ai oublié, voici les fichiers pour ceux que ça intéresse ...
    Fichiers attachés Fichiers attachés

  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
    Citation Envoyé par einboubou Voir le message
    Sinon pour le fait que c'est limité à Mysql, c'est pas si grave car c'était juste un petit script comme ça.
    Ben c'est un peu con car il faut peu de chose pour en faire une classe générique qui fonctionnerait avec toutes les BDs...

    Citation Envoyé par einboubou Voir le message
    Le available fonctionne pour ma part.
    Humm... Disons que ca tombe en marche

    La doc officiel d'available() indique bien qu'il s'agit uniquement d'une estimation du nombre de donnée qui peut être lu sans blocage, et qu'il ne faut surtout pas utiliser cette valeur pour initialiser un buffer...


    Citation Envoyé par einboubou Voir le message
    Sinon j'ai pas bien compris la remarque Tu pourrais m'indiquer de quelle ligne tu parle ?
    Dans ta méthode insertImage(), tu fais un select puis un update sur les résultats...

    Pourquoi ne pas faire directement un INSERT ou un UPDATE SQL ?


    a++

  7. #7
    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
    Je viens de voir tes fichiers...


    Pour moi même ta connection ne devrait pas être static...

    Quand aux try/finally, tu devrais en avoir un par ressources pour être sur de tout bien libérer dans tous les cas...

    a++

  8. #8
    Nouveau membre du Club
    Inscrit en
    Avril 2009
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Avril 2009
    Messages : 48
    Points : 38
    Points
    38
    Par défaut
    Citation Envoyé par adiGuba Voir le message
    Ben c'est un peu con car il faut peu de chose pour en faire une classe générique qui fonctionnerait avec toutes les BDs...
    Je ne savais pas trop comment remplacer ces lignes pour les rendres génériques :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    rsImage.updateBytes("imageNormalModel", bytes);
    rsImage.updateBytes("imageResizedModel", bytesMini);
    A moins que quelque soit la base il faudrait utiliser le updateBytes ? Je ne sais pas c'est la première fois que j'utilise une SGDB avec du java.


    Citation Envoyé par adiGuba Voir le message
    Humm... Disons que ca tombe en marche

    La doc officiel d'available() indique bien qu'il s'agit uniquement d'une estimation du nombre de donnée qui peut être lu sans blocage, et qu'il ne faut surtout pas utiliser cette valeur pour initialiser un buffer...
    Ok faudra que je me penche dessus. J'avoue que je ne lis pas assez la doc :p



    Citation Envoyé par adiGuba Voir le message
    Dans ta méthode insertImage(), tu fais un select puis un update sur les résultats...

    Pourquoi ne pas faire directement un INSERT ou un UPDATE SQL ?
    Parce que je ne sais pas trop comment faire pour insérer une image. Avant je faisais un :
    Puis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    rsImage.moveToInsertRow();
    Mais à la fin j'avais une table de plus en plus grosse, à cause des images, donc java tombait :p
    J'ai donc préféré faire un insert de l'id avec la méthode newImage() avant puis un :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select * from T_MODEL where idModel="+id
    et après je peux mettre à jour le blob. Je ne savais pas comment faire un insert directement dans les blob. Je met quoi dans la requète SQL Je sais c'est un peu bancal mais ça fonctionnait comme ça :p

Discussions similaires

  1. [Tableaux] optimisation pour grosse quantité
    Par mdr_cedrick dans le forum Langage
    Réponses: 7
    Dernier message: 30/04/2008, 18h31
  2. dll C++ et grosse quantité de variables
    Par antiseche dans le forum MATLAB
    Réponses: 1
    Dernier message: 29/03/2008, 01h10
  3. Réponses: 1
    Dernier message: 14/09/2007, 22h34
  4. texte+ photo +carte mémoire
    Par Vestigo dans le forum Composants
    Réponses: 4
    Dernier message: 12/09/2007, 16h32
  5. Paralleliser traitements grosse quantité donnee
    Par Sébastien P dans le forum Développement 2D, 3D et Jeux
    Réponses: 8
    Dernier message: 13/04/2007, 19h28

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