Recherche XML qui fait exploser la mémoire !
mpergand
Membre
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:
J'ai essayé de rajouter un autoReleasePool dans la boucle, sans succès.
Je vois pas trop quoi faire
Une idée ?
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)Outre le fait que c'est super lent, la mémoire occupée grimpe jusqu'à 3 Go et l'appli crash avec malloc_error !
{
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]];
}
}
J'ai essayé de rajouter un autoReleasePool dans la boucle, sans succès.
Je vois pas trop quoi faire
Une idée ?
Connectez-vous ou Inscrivez-vous pour répondre.
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.
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 ...
Choisir son XML Parser en fonction de son besoin
Oui, je connais
Salut Aligator,
Instruments ?
Il plante à ~ 4 Go d'allocations Overall et All Allocations ~ 500 Mo
J'ai fait un screen avant plantage:
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.
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.
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
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
Salut à tous,
Alors il s'agit d'un XML de type Content.opf des fichiers ePub
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)
/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.
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 ::)