Recherche XML qui fait exploser la mémoire !

mpergandmpergand Membre
juillet 2013 modifié dans API AppKit #1
Salut à  tous,
 
J'ai  besoin de rechercher la correspondance d'un attribut  (pour ~2000 éléments) dans une table de ~5000 éléments.
 
Voici le code:
for(NSXMLElement* item in itemRefs)
{
NSXMLNode* idRef=[item attributeForName:@idref];
// recherche dans manifest l'item ayant l'attribut id égal à  idRef
NSString* query=[NSString stringWithFormat:@"./item[@id=\"%@\"]",[idRef stringValue]];
NSArray* hrefs=[manifest nodesForXPath:query error:nil];

if([hrefs count])
{
NSXMLElement* href=[hrefs objectAtIndex:0];
[iPages addObject:[[href attributeForName:@href] stringValue]];
}
}

Outre le fait que c'est super lent, la mémoire occupée grimpe jusqu'à  3 Go et l'appli crash avec malloc_error !
 
J'ai essayé de rajouter un autoReleasePool dans la boucle, sans succès.
 
Je vois pas trop quoi faire  B)
 
Une idée ?

Réponses

  • Tu as manifestement un très gros fichier XML.


    Du coup une méthode tree-based comme celle que tu utilises (avec NSXML) n'est pas efficace car le fichier est dupliqué dans une structure arborescente en mémoire.


    Il vaut mieux utiliser dans ton cas un parser orienté événement comme NSXMLParser.


  • mpergandmpergand Membre
    juillet 2013 modifié #3

    Merci de ta réponse.


     


    Le fichier fait 550K et est déjà  chargé en mémoire, c'est la recherche qui pose problème.


     


    J'ai essayé d'optimiser la recherche par: item[@id=\"%@\"][1] ou (item[@id=\"%@\"])[1]


    qui devrait stopper la recherche au premier élément trouvé, mais pas mieux !


     


    Je sens que je vais faire cette recherche à  la mano ...


  • AliGatorAliGator Membre, Modérateur
    C'est quoi au juste qui fait grimper autant la mémoire (d'après Instruments) ?
  • Choisir son XML Parser en fonction de son besoin :D


  • mpergandmpergand Membre
    juillet 2013 modifié #6


    Choisir son XML Parser en fonction de son besoin :D




     


    Oui, je connais :)


     


     


     




    C'est quoi au juste qui fait grimper autant la mémoire (d'après Instruments) ?




     


    Salut Aligator,


     


    Instruments ?


    Il plante à  ~ 4 Go d'allocations Overall et All Allocations ~ 500 Mo


    J'ai fait un screen avant plantage: 




  • Le fichier fait 550K et est déjà  chargé en mémoire, c'est la recherche qui pose problème.




     


    Effectivement le fichier n'est pas si gros et ne peut expliquer à  lui seul 3Go d'empreinte mémoire.


     


    +1 sur le post d'Aligator : il faut savoir précisément ce qui fait grimper la mémoire.

  • mpergandmpergand Membre
    juillet 2013 modifié #8

    Mes investigations avec instruments ne m'apprennent pas grand chose de nouveau.


     


    Le problème vient bien de la ligne: NSArray* hrefs=[manifest nodesForXPath:query error:nil];


     


    Test avec une recherche sur 10 éléments seulement (y en a 2100 !)


    la somme des plus gros leaks (tous liés à  XQuery) fait  20Mo.


     


    Une recherche sur 300 éléments pompe 500 Mo et ça pête quand la mémoire atteint 3 Go (1800 éléments).


     


    C'est quand même très curieux cette histoire.


  • AliGatorAliGator Membre, Modérateur
    Lors de tes tests avec moins d'éléments, la mémoire monte quand même beaucoup, mais est-ce qu'à  la fin elle redescend ou bien est-ce qu'elle reste et que c'est donc un leak (qui serait donc un bug de gestion mémoire dans le code Apple) ?


    Sinon c'est peut-être pas idéal mais ne pourrais-tu pas changer d'approche et récupérer tous les noe“uds "item" (avec un Xpath, certes, mais qui sera plus simple et peut être moins bouffe-mémoire ?) et te construire un NSDictionary de ces noe“uds indexés sur leur attribut "id" pour faire ton mapping ensuite ?

    En plus ça sera très certainement plus rapide car ton Xpath n'aura, pour trouver tes noe“uds "id", qu'à  faire un seul parcours d'arbre (plutôt qu'autant de parcours d'arbres, certes partiels mais multiples quand même) que d'id que tu as, et après la mise dans un NSDico ne sera pas si longue que ça... avec beaucoup de noe“uds item comme ça semble être ton cas à  mon avis ça va être bénéfique... en tout cas ça vaut le coup de tenter
  • MalaMala Membre, Modérateur

    Je suis surpris car j'utilise le parser DOM d'Apple avec des requêtes Xpath depuis des années sur des centaines de fichiers tous les jours dont certains font plus de 30Mo sans aucun soucis. Y a moyen de poster ton XML? 


  • Tu peux essayer de récupérer directement l'attribut :


    ./item[@id=\"%@\"]/@href

  • mpergandmpergand Membre
    juillet 2013 modifié #12

    Salut à  tous,


     


    Alors il s'agit d'un XML de type Content.opf des fichiers ePub



    - Content.opf
    This file gives a list of all files in the .epub container, defines the order of files, and stores meta data (author, genre, publisher, etc.) information.
    Note that this file can be named anything you want to call it, as long as the container.xml file mentioned above points to the correct filename.

    <?xml version="1.0" encoding="UTF-8"??>
    <package xmlns="http://www.idpf.org/2007/opf" unique-identifier="BookID" version="2.0" >
    <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
    <dc:title>Sample .epub eBook</dc:title>
    <dc:creator opf:role="aut">Yoda47</dc:creator>
    <dc:language>en-US</dc:language>
    <dc:rights>Public Domain</dc:rights>
    <dc:publisher>Jedisaber.com</dc:publisher>
    <dc:identifier id="BookID" opf:scheme="UUID">jedisaber06282007214712</dc:identifier>
    </metadata>
    <manifest>
    <item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml" />
    <item id="style" href="stylesheet.css" media-type="text/css" />
    <item id="pagetemplate" href="page-template.xpgt" media-type="application/vnd.adobe-page-template+xml" />
    <item id="titlepage" href="title_page.xhtml" media-type="application/xhtml+xml" />
    <item id="chapter01" href="chap01.xhtml" media-type="application/xhtml+xml" />
    <item id="chapter02" href="chap02.xhtml" media-type="application/xhtml+xml" />
    <item id="imgl" href="images/sample.png" media-type="image/png" />
    </manifest>
    <spine toc="ncx">
    <itemref idref="titlepage" />
    <itemref idref="chapter01" />
    <itemref idref="chapter02" />
    </spine>
    </package>

    L'exercice consiste pour tous les itemRef de <spine> rechercher l'item correspondant dans <manifest>


     


    Donc, je vais chercher le noe“ud <manifest>


    [iOPFxml nodesForXPath:@manifest error:nil];


    puis le noe“ud <spine>


    [iOPFxml nodesForXPath:@spine error:nil];


    puis tous les itemRef


    [spine nodesForXPath:@itemref error:nil];


    enfin je fais la recherche pour tous les itemRef (boucle for)


  • FKDEVFKDEV Membre
    juillet 2013 modifié #13

    /package/manifest/item[@id=/package/spine/itemref/@idref]/@href


     


    Bon je sais je ne réponds pas vraiment à  la question mais là  on va avoir du mal à  aller plus loin sans avoir accès à  plus d'information.


  • mpergandmpergand Membre
    juillet 2013 modifié #14

    Epilogue


     


    @Mala m'a fourni un utilitaire pour tester les recherches XPath.


    La recherche met 3/4 minutes pour s'accomplir, la mémoire occupée dépasse les 3 Go,  mais l'appli ne plante pas car en 64 bits !


     


    Une petite méthode perso, vite fait, en passant par un dico, accompli la recherche en 10/12 secondes et 300 Mo de mem.


     


    En conclusion, on peut donc dire que que les recherches XPath ne sont pas très optimisées chez la pomme  ::)


Connectez-vous ou Inscrivez-vous pour répondre.