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 :

Comment économiser de la mémoire ?


Sujet :

JDBC Java

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2006
    Messages : 14
    Points : 8
    Points
    8
    Par défaut Comment économiser de la mémoire ?
    Bonjour,

    Mon appli java doit copier des données d'une base vers une autre.
    Concrètement j'ai deux connections, d'un coté je fais un select et de l'autre un insert.Jusque la tout va bien.

    Mon soucis : certaines tables contiennent des GROS BLOBs et là :
    "Exception in thread "main" java.lang.OutOfMemoryError: Java heap space"

    Sur mon poste ca passe en changeant les paramètres de la JVM :
    "-Xms256m -Xmx1024m"

    Mais une fois en prod ca ne sera pas toujours possible, il faut que j'economise de la mémoire. Voici quelques questions que je me suis posées, pour lesquelles je n'ai pas encore trouvé les réponses :

    quand j'exécute :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    resultSet = statement.executeQuery(query);
    Le ResultSet contient il en mémoire l'ensemble des résultats ?

    Si oui, peut on faire en sorte qu'il les charge "au fur et à mesure" ?

    Pour les insertions j'ai désactivé l'autocommit, l'ensemble des inserts non validés (commit) sont il chargés en mémoire coté JVM ?

  2. #2
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2006
    Messages : 14
    Points : 8
    Points
    8
    Par défaut interprétation ou vérité
    Dans la doc de sun, http://java.sun.com/.../database.html, il y a un paragraphe sur les Resultsets et un sur les transactions.

    Ca ne semble pas explicite, mais je comprends que les Resultset manipulent en fait un curseur géré par la DBMS. De même, les transactions sont gérées par le DBMS.
    Dans ce cas, je ne vois pas comment consommer moins de mémoire lors de mon SELECT/INSERT...

    Merci de partager votre avis ...

  3. #3
    Membre confirmé

    Homme Profil pro
    Chomeur
    Inscrit en
    Juin 2006
    Messages
    347
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Chomeur

    Informations forums :
    Inscription : Juin 2006
    Messages : 347
    Points : 452
    Points
    452
    Par défaut
    Salut Bashar,

    Pour ce qui est de la gestion des resultsets, effectivement au moins une partie de la transaction est gere par la BD: elle retourne le nombre total de row entre autre et c'est cette action qui est extremement couteuse en ressources et en temps (pour ca, il faut que le pointeur parcours l'ensemble des resultats pour les compter). Voila une petite source qui peut peut etre aider. Pour ceux qui ne connaissent pas AskTom est le site de Tom Kyte qui est grosso modo le mec le plus baleze du monde en base Oracle (il bosse la bas et c'est ce que dise les autre gourous d'Oracle):
    http://asktom.oracle.com/pls/asktom/...:4456921593765


    Le ResultSet contient il en mémoire l'ensemble des résultats ?
    OUI

    peut on faire en sorte qu'il les charge "au fur et à mesure" ?
    OUI, voir le lien au dessus

    l'ensemble des inserts non validés (commit) sont il chargés en mémoire coté JVM ?
    La je suis pas trop sur mais je ne pense pas, a priori ca devrait plutot etre a la base de conserver la mise en queue des transactions non committe (si quelqu'un peut preciser...)

    Derniere petite chose, j'ai fait aussi un peu d'upload et download en java et meme en uploadant un par un des fichiers je finissais regulierement par tomber sur cette errreur (jusqu'a ce que comme toi je modifie le heap space). Je me demande si il n'y a pas une espece de mise en cache au niveau de la JVM (genre un garbage collector un peu lent ou ???) qui provoque un effet cumulatif en saturation de la memoire au fur et a mesure des upload.

    En tout cas bon courage,
    Cordialement,
    Tif

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2006
    Messages : 14
    Points : 8
    Points
    8
    Par défaut
    Merci beaucoup !!

    C'est une vrai mine d'or ce site, je ne connaissais pas !

    Du coup le seul moyen dont je dispose est de ne plus utiliser les :
    resultSet.last() et resultSet.getRow()

    je vais tester de ce pas

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2006
    Messages : 14
    Points : 8
    Points
    8
    Par défaut
    Voila...j'ai fais mes tests...
    En fait, à l'exécution du query, tout le résultat est chargé et les objects instanciés dans la JVM.

    Pour en savoir plus j'ai essayé JConsole (merci Gfx : Le garbage collector)

    lors de l'exécution de la ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    resultSet = statement.executeQuery(query);
    La conso mémoire monte en flèche jusqu'à la taille (environ) de ma table
    dans le cas présent 1GB

    Je vais fouiller plus avant sur AskTom, mais si quelqu'un à une idée pour éviter de charger toute la table...

  6. #6
    Membre confirmé

    Homme Profil pro
    Chomeur
    Inscrit en
    Juin 2006
    Messages
    347
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Chomeur

    Informations forums :
    Inscription : Juin 2006
    Messages : 347
    Points : 452
    Points
    452
    Par défaut
    Salut Bashar,

    Une solution (de facilité) pourrai etre l'utilisation de "ROWNUM". Par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    SELECT * FROM MATABLE WHERE ROWNUM < 6
    Ne renverra que les 5 premiers résultats de la requete. (Maintenant faut voir ce qu'il fait du reste mais il me semble qu'il ne parcours et ne charge que jusqu'à avoir trouvé les 5 premiers)

    Ensuite tu te débrouille pour lui passer des parametres du genre "rownum > 5 and rownum < 11", ...
    Ca devrai aider, mais il y a probablement une solution encore meilleure

    Bon courage,
    Tif

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2006
    Messages : 14
    Points : 8
    Points
    8
    Par défaut
    Tout à fait d'accord, je planchais sur ce genre de solution...modifier le query pour ne ramener qu'un enreg à la fois...

    Toutes mes tables n'ont pas de PK (je n'ai pas la main sur le modèle)
    La table sur laquelle je "coince" comporte 4 LONGBLOB...soit 16Go max

    Je sais que ROWNUM n'est pas supporté par MySQL, mais sans doute il existe un équivalent, je vais creuser ca.

    Ca m'étonne quand meme qu'un ResultSet contienne forcément en mémoire l'intégralité des résultats du query...N'y aurait il pas un autre moyen "java" de limiter le volume de données remontées ?

  8. #8
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2007
    Messages : 132
    Points : 170
    Points
    170
    Par défaut
    Un moyen d'éconimiser ta taille mémoire est de lire ta table par page.

    Tu lis les 50 premier elements
    Puis les 50 autres etc...

    tu ne peux pas utliser la méthode setfetchSize car au fur et à mesure que tu liras ta table, les objects seront en mémoire et donc ta mémoire augmentera.

    Tu peux utiliser les scroll curseurs, mais c'est plus ou moins bien implementers suivant les Bases de données.

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2006
    Messages : 14
    Points : 8
    Points
    8
    Par défaut Ca y est j'ai trouvé !
    D'abord merci à tous pour votre aide !

    La ou je grimpais à 1Go dans la JVM je ne dépasse plus les 180Mo

    En fait, j'utilise le setFetchSize()...j'ai trouvé ca sur le site de MySQL en cherchant des solutions de contournement du ROWNUM...
    Pour ceux que ca interesse c'est ici

    Dans la mesure ou les pilotes JDBC sont fournis par les editeurs des SGBD, sans doute avec une autre version ou un autre SGBD ca aurait eu l'effet d'empilement dont parle elmor, heureusement pour moi ca n'est pas le cas ici

  10. #10
    Expert éminent
    Avatar de elitost
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Septembre 2003
    Messages
    1 985
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2003
    Messages : 1 985
    Points : 6 566
    Points
    6 566
    Par défaut
    Citation Envoyé par Bashar
    D'abord merci à tous pour votre aide !

    La ou je grimpais à 1Go dans la JVM je ne dépasse plus les 180Mo

    En fait, j'utilise le setFetchSize()...j'ai trouvé ca sur le site de MySQL en cherchant des solutions de contournement du ROWNUM...
    Pour ceux que ca interesse c'est ici

    Dans la mesure ou les pilotes JDBC sont fournis par les editeurs des SGBD, sans doute avec une autre version ou un autre SGBD ca aurait eu l'effet d'empilement dont parle elmor, heureusement pour moi ca n'est pas le cas ici
    Tu vois, tu viens d'avoir une réponse satisfaisante, qui intéressera du monde (moi déjà)...merci de l'avoir posée.

    Maintenant si pour toi, c'est résolu il faut cliquer sur le bouton

    Bonne continuation dans tes tests

  11. #11
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2006
    Messages : 14
    Points : 8
    Points
    8
    Par défaut
    Merci Eric

    Avant de valider mes tests, il me reste à creuser sur XStream pour alléger mon fichier d'échange...je te ferais signe si je post en cas de difficulté
    Les Converter ne me semblent pas clair

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    511
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 511
    Points : 386
    Points
    386
    Par défaut
    Je ne pige pas ! Pourquoi ne pas transférer les données d'une table à l'autre via le sql même s'il faut une tripatouillée de requêtes, c'est tellement plus simple et plus de pb de mémoire.

  13. #13
    Expert éminent sénior
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Points : 12 977
    Points
    12 977
    Par défaut
    Tout simplement car ce n'est pas d'un transfert entre deux tables que Bashar cherchait à faire mais un transfert entre deux bases (ensuite je ne sais si les deux sont les mêmes (ie, 2 MySQL ou 2 Oracle), car dans ce cas là il y aurait eu des contournements selon le SGBD: DBLINK sous Oracle par exemple)

  14. #14
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2006
    Messages : 14
    Points : 8
    Points
    8
    Par défaut
    Tout à fait Sinok.
    Pour l'instant il s'agit de deux base MySQL mais il est envisagé qu'un jour ca change...

    Par ailleurs, une fois le projet mis en prod, l'équipe sera fortement reduite et il n'est pas certain qu'il y aura des compétences SQL pour gérer les script dont parle George. Pour le reste de l'applicatif, SQL n'est pas requis puisque la persistance est gérée par JDO.

    Un autre soucis avec les scripts c'est les longblobs...C'est un peu lourd a gérer, il n'est pas possible de les mettre directement dans une requete, ensuite ca risque de coincer à plusieurs endrois à cause des volumes...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Outils][VB.NET] Comment observer la charge mémoire ?
    Par blau dans le forum EDI/Outils
    Réponses: 1
    Dernier message: 20/01/2006, 10h12
  2. Réponses: 11
    Dernier message: 13/01/2006, 15h30
  3. [Interfaces] Comment définir l'emplacement mémoire des methodes ?
    Par Clorish dans le forum API, COM et SDKs
    Réponses: 2
    Dernier message: 16/12/2005, 14h45
  4. Réponses: 3
    Dernier message: 28/06/2005, 09h07
  5. Comment bien gerer la mémoire avec les TStringList?
    Par david_chardonnet dans le forum Langage
    Réponses: 5
    Dernier message: 18/06/2003, 09h57

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