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

Persistance des données Java Discussion :

Castor + gros fichier XML = java.lang.StackOverflowError


Sujet :

Persistance des données Java

  1. #1
    Futur Membre du Club
    Inscrit en
    Mars 2008
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Mars 2008
    Messages : 9
    Points : 6
    Points
    6
    Par défaut Castor + gros fichier XML = java.lang.StackOverflowError
    Salut à tous !

    Voici mon problème.
    Je travaille sur un projet qui nécessite d'instancier des objets java à partir de fichiers XML. Castor fait exactement ça.

    Ma situation est assez simple.

    J'utilise d'abord Castor pour créer un fichier XML : test.xml en faisant du marshalling(sérialisation) d'un objet Person (celui des exemples du site de castor).
    Ensuite, je fais l'inverse, et j'unmarshall (désérialise) test.xml pour récupérer un deuxième objet Person. Les deux sont identiques => Ok.

    Le fichier test.xml généré par le Marshaller :
    <person>
    <name>Ryan</name>
    <date-of-birth>2000-10-10T00:00:00.000+02:00</date-of-birth>
    </person>
    Ça semble Ok.

    Mais j'ai besoin de désérialiser de GROS fichiers XML (~1Go) dans un environnement de production.
    Donc, j'ajoute des gros nodes à mon fichier test.xml généré plus haut, jusqu'à ce que celui-ci fasse 1Go.
    La structure du fichier reste la même :
    <person>
    <movement>.....</movement>
    // pleins de nodes <movement> ici
    <name>Ryan</name>
    <date-of-birth>2000-10-10T00:00:00.000+02:00</date-of-birth>
    </person>

    Quand je désérialise ce fichier de 1Go, j'attrape l'exception :
    Exception in thread "Main Thread" java.lang.StackOverflowError
    at org.exolab.castor.xml.Namespaces.getNamespaceURI(Namespaces.java:206)
    ...


    Je n'utilise pas de fichier de mapping.
    paramètres JVM :
    -Xmx1024m.
    -Taille de la JVM au moment du crash: 70Mo ~

    Fichiers attachés :
    Person.java : L'objet Person vers lequel désérialiser
    TestIt.java : La classe de test
    test.xml : Fichier généré par la sérialisation de l'objet Person, que j'ai ensuite désérialisé. Tout est Ok avec ce fichier.
    112.xml : Fichier test.xml auquel j'ai ajouté un node <movement>. désérialisation Ok
    Lorsque mon fichier 112.xml fait 1Go (en gros quand j'ajoute un bon paquet de nodes <movement> les uns derrière les autres, impossible de désérialiser


    Quelqu'un peut m'aider ou connait un outil permettant de faire de la désérialisation de gros fichier tel que celui-là ? ?

  2. #2
    Futur Membre du Club
    Inscrit en
    Mars 2008
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Mars 2008
    Messages : 9
    Points : 6
    Points
    6
    Par défaut
    Une petite idée ? Personne ?
    Une aide serait vraiment très appréçiée.
    Merci

  3. #3
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 937
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 937
    Points : 4 358
    Points
    4 358
    Par défaut
    Citation Envoyé par spooon Voir le message
    Une petite idée ? Personne ?
    Une aide serait vraiment très appréçiée.
    Merci
    Un Parser SAX peut aider…

    mais tout dépend de la taille des "unités/chunks" qu'il faut traiter…
    (même avec un parser SAX si vous vous amusez à reconstruire tout l'arbre en mémoire vous pouvez retomber sur le problème du out-of-memory…)

    1 Gb peut-être un gros objet (une "unité") de 1 Gb ou des milliers de petits objets traitables séparément…

    à vous d'analyser l'empreinte minimum de votre code : quel est le nombre d'objets inter-reliés qu'il faut traiter en même temps (garder ensemble en mémoire) avant de pouvoir les oublier et passer au groupe suivant…
    (si vous ne pouvez pas séparer le traitement logique du fichier en lots, vous aurez de toute façon le problème - plus ou moins loin dans le traitement - quel que soit le type de parser…)

    c'est ce qui déterminera la taille mémoire minimum nécessaire à allouer au process… et si cela excéde ce que vous pouvez allouer sur votre plate-forme, c'est qu'il faut passer à autre chose…

  4. #4
    Futur Membre du Club
    Inscrit en
    Mars 2008
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Mars 2008
    Messages : 9
    Points : 6
    Points
    6
    Par défaut
    Je comprend tout à fait !
    Cela voudrait dire qu'ici, mon unité <person> est trop grosse, ce qui n'est pas le cas de mes entités dans mon environnement de production, où les entité pouvant être traités de façon unitaire font moins de 1Mo, mais son en très grand nombre dans le fichier XML.

    Actuellement, mon application tourne avec une librairie Castor 0.9.7.
    le fonctionnement est le suivant.
    Le fichier à utiliser contient un grand nombre de <commande>, chacune devant être traitée séparément.
    Les commandes instanciées sont mise dans un pull de commande.
    Ce pull de commande alimente un handler qui va traiter une à une les commandes.
    Dans l'ordre, les étapes sont :

    1/ Unmarshalling du fichier de 500Mo~ (fichier qui va dépasser les 1Go à la prochaine version), et instançiation des objets commandes
    2/ Traitement des commandes (écriture en base etc...)

    Si j'ai bien compris ce que tu me dis JeitEmgie, il est possible de commander le comportement du parser de Castor. Serait-il possible que le parser s'arrête dans son instanciation, et "attende" que le nombre de commande dans le pull de commandes disponibles passe en dessous d'un seuil, avant de le réalimenter avec de nouvelles commandes fraichement parsées, et donc d'utiliser moins de mémoire ?

  5. #5
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 937
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 937
    Points : 4 358
    Points
    4 358
    Par défaut
    Citation Envoyé par spooon Voir le message
    Je comprend tout à fait !
    Cela voudrait dire qu'ici, mon unité <person> est trop grosse, ce qui n'est pas le cas de mes entités dans mon environnement de production, où les entité pouvant être traités de façon unitaire font moins de 1Mo, mais son en très grand nombre dans le fichier XML.

    Actuellement, mon application tourne avec une librairie Castor 0.9.7.
    le fonctionnement est le suivant.
    Le fichier à utiliser contient un grand nombre de <commande>, chacune devant être traitée séparément.
    Les commandes instanciées sont mise dans un pull de commande.
    Ce pull de commande alimente un handler qui va traiter une à une les commandes.
    Dans l'ordre, les étapes sont :

    1/ Unmarshalling du fichier de 500Mo~ (fichier qui va dépasser les 1Go à la prochaine version), et instançiation des objets commandes
    2/ Traitement des commandes (écriture en base etc...)

    Si j'ai bien compris ce que tu me dis JeitEmgie, il est possible de commander le comportement du parser de Castor. Serait-il possible que le parser s'arrête dans son instanciation, et "attende" que le nombre de commande dans le pull de commandes disponibles passe en dessous d'un seuil, avant de le réalimenter avec de nouvelles commandes fraichement parsées, et donc d'utiliser moins de mémoire ?
    je n'utilises pas Castor donc je n'en sais rien…

    mais un parser de type SAX càd un parser qui appelle vos callbacks sur les éléments XML qu'il rencontre, vous permet de gérer votre machine d'états et ainsi de contrôler l'empreinte mémoire laissée par vos structures…

    (par opposition à un parser DOM qui charge tout le document en mémoire…)

  6. #6
    Futur Membre du Club
    Inscrit en
    Mars 2008
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Mars 2008
    Messages : 9
    Points : 6
    Points
    6
    Par défaut
    Merci JeitEmgie pour ton aide. Ceci m'éclaire un peu.

    Je vais maintenant me documenter sur la manière de piloter le parser de Castor, afin d'éviter l'explosion de l'utilisation mémoire.
    si quelqu'un sait comment faire cela, je suis extrêmement intéressé.

  7. #7
    Futur Membre du Club
    Inscrit en
    Mars 2008
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Mars 2008
    Messages : 9
    Points : 6
    Points
    6
    Par défaut
    Le problème ne venait pas de castor, mais de la manière de l'utiliser.
    Aujourd'hui, j'utilise un stringbuffer pour découper le fichier xml en petits noeuds que je traite séparément, plutot que de demander à castor de créer un gros objet contenant le résultat de la désérialisation du fichier xml entier de départ.

    En pilotant castor avec un pool, j'arrive à diminuer la RAM utilisée de 99%, victoire donc.

    Fonction pour découper mon XML en petits noeuds :
    getElement(reader, "mouvement", log)
    ramène un string contenant le noeud <mouvement>[...]</mouvement>
    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
     
    private static String getElement(java.io.Reader r, String element, Log log) throws IOException {
        	boolean end = false;
        	boolean first = true;
        	String chDebut = "<" + element + ">";
        	String chFin = "</" + element + ">";
        	StringBuffer sb = new StringBuffer();
        	int nbCar = 0;
        	int nSkip = 0;
        	while(!end) {
        		r.mark(30000);
        		char[] buf = new char[30000];
        		int nbCarLu = r.read(buf);
        		sb.append(buf);
        		r.reset();
        		if (first) {
        			int deb = sb.indexOf(chDebut);
        			if (deb == -1) {
        				return null;
        			}
        			first = false;
        		}
            	int fin = sb.indexOf(chFin);
            	if (fin == -1 && nbCarLu < 30000) {
            		return null;
            	} else if (fin == -1) {
            		nSkip += 30000;
            		r.skip(30000);
            	} else {
            		nbCar = fin + chFin.length();
            		int skip = nbCar - nSkip;
            		r.skip(skip);
            		end = true;
            	}
        	}
        	return sb.substring(sb.indexOf(chDebut), nbCar);
        }
    ensuite, je traite mon string :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    sr = new StringReader(getElement(b,"mouvement", log));
    Mouvement m = (Mouvement) Unmarshaller.unmarshal(Mouvement.class, sr);
    Et voilà
    Merci pour l'aide.

Discussions similaires

  1. serialisation et java.lang.StackOverflowError
    Par LittleBean dans le forum Langage
    Réponses: 3
    Dernier message: 11/04/2007, 10h29
  2. Réponses: 2
    Dernier message: 15/03/2007, 14h00
  3. java lang StackOverflowError
    Par kokumbo dans le forum Langage
    Réponses: 3
    Dernier message: 05/12/2006, 16h01
  4. Transformer un très gros fichier XML avec XSL
    Par wozzz dans le forum Format d'échange (XML, JSON...)
    Réponses: 3
    Dernier message: 30/05/2006, 10h57
  5. [C#] [XML] Traitement de gros fichiers XML (90 Mo)
    Par Pulsahr dans le forum Windows Forms
    Réponses: 20
    Dernier message: 01/12/2005, 14h40

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