Consommation mémoire hallucinante en parsant des fichiers xml

zeuszeus Membre
mars 2006 modifié dans API AppKit #1
Bonjour,

Je suis en train d'écrire un programme qui est amené à  parser une très grosse quantité de fichier xml (plusieurs dizaines de milliers). J'ai donc opté pour un NSXMLParser qui est un parseur événementiel, afin d'éviter de créer une représentation en mémoire du fichier xml courant. Jusque là  tout vas bien. Là  où les choses commence à  se gâter, c'est quand je regarde l'occupation mémoire dudit programme. Lorsque je parse juste une centaine de fichier j'arrive déjà  à  une consomation mémoire de 212 Mb et 477 Mb de virtuelle. J'ai bien évidemment été vérifier avec ObjectAlloc si je n'avais pas un memory leackage et cela ne semble pas être le cas. J'ai aussi lancer mon application via MallocDebug et là  pour le coup le programme m'indique que j'occupe 2Mb d'espace mémoire.

Comment dois-je faire pour que MallocDebug m'indique effectivement là  ou je consomme la mémoire (car je ne pense pas que la commande top reporte un consommation mémoire erronée)?

Merci d'avance.

Jérôme

[EDIT]

Je viens de jouer un peu avec l'outils en ligne de commande qui se nomme "leaks" et, la, je constate que: primo ,j'ai le framework de cocoa qui leaks ,mais en plus de ça j'ai cette ligne forte intéressante:

Process 1108: 20008 nodes malloced for 2173 KB


Ce qui tendrait à  prouver que je consomme bien 2Mb de ram. Alors pourquoi diable la commande top m'indique que 113 Mb sont alloué. Ce qui me semble très douteux, c'est que quand je parse un plus grand nombre de fichiers et que mon allocation mémoire dépasse le 1,65 Gb j'ai bien l'impression que le système swap (j'ai 2 Gb de ram). Des idées.

[/EDIT]

Réponses

  • 07:27 modifié #2
    Règle n°1 évite l'utilisation des éléments auto releasés dans les éventuels traitements quand c'est possible.
  • zeuszeus Membre
    07:27 modifié #3
    dans 1143571691:

    Règle n°1 évite l'utilisation des éléments auto releasés dans les éventuels traitements quand c'est possible.


    Je dois dire que je n'y croyais pas trop à  cette idée d'éviter les éléments auto releasés, mais suite  à  un refactoring du code, j'ai essayé, quand même, pour voir ce que ça donnait. Et bien, je dois dire qu'après quelques tests préliminaire et la suppression de 4 éléments auto releasés (qui était dans des objets instanciés environ 1000 fois), j'ai pu diminué de plus 50% mon empreinte mémoire. Tout ceci sans parler du gain de temps lors de l'exécution.

    Je vais donc encore me promener dans mon code voir si je n'ai pas d'autres candidats à  l'éradication du auto release.

    En tout cas merci Renaud pour l'idée.  :adios!:
  • 07:27 modifié #4
    Si vraiment tu ne sais pas éviter l'utilisation d'éléments autoreleasés, tu peux créer tes propres autorelease pool dans les boucles genre:

    [tt]
    NSAutoreleasePool *pool;
    for ( i=0 ; i < x ; i++ ) {
    pool = [NSAutoreleasePool new];

    // ton code

    [pool release];
    }[/tt]

    ça aide aussi.
  • AliGatorAliGator Membre, Modérateur
    07:27 modifié #5
    D'auatnt que des fois on est même obligé de passer par la solution que vient de proposer Renaud, car certaines méthodes utilisent des éléments autoreleasés en interne et donc on ne peux pas contrôler leur utilisation...

    Et il semble qu'Apple n'ait pas mis des autoreleasepool forcément partout non plus où ça aurait pu être nécessaire, dans son code "interne" :(
    (Je pense en particulier aux grosses boucles travaillant sur les images, qui semblent garder en mémoire des objets temporaires jusqu'à  la fin de la RunLoop, même si on a pris soin de notre côté de n'utiliser que des objets non autorelease)
  • zeuszeus Membre
    07:27 modifié #6
    Voila comme j'aime bien les fils de discussion qui se termine par une explication de comment résoudre le problème, je vais vous exposez la solution à  mon problème de consommation mémoire. Dans l'ordre voici ce que j'ai fait:

    • J'ai supprimé au maximum la création d'objets auto releasés. => diviser l'empreinte mémoire par 2
    • J'ai ajouté ma propre autorelease pool dans ma boucle principale. => diviser l'empreinte mémoire par 6


    Donc au final j'ai diminué l'empreinte mémoire de mon application d'un facteur 12, pas mal non.

    Je pense que la diminution liée à  la gestion de sa propre autorelease pool est particulièrement importante dans mon cas, de par le fait que je parse beacoup de fichiers et que dans cette opération je manipule beaucoup de NSMutableString (qui doivent utiliser quelque part des mécanisme de autorelease).

    Merci encore a Renaud.
  • AliGatorAliGator Membre, Modérateur
    07:27 modifié #7
    dans 1144964480:

    • J'ai supprimé au maximum la création d'objets auto releasés. => diviser l'empreinte mémoire par 2
    • J'ai ajouté ma propre autorelease pool dans ma boucle principale. => diviser l'empreinte mémoire par 6


    Donc au final j'ai diminué l'empreinte mémoire de mon application d'un facteur 12, pas mal non.
    Noonn ? A ce point ?
    J'avais apris ici en effet que sur des grosses boucles ça faisait du bien (merci OC), mais je pensais pas que ça pouvait gagner à  ce point... c'est énorme !!

    Toujours bon à  noter, ça va me donner envie d'y réfléchir plus souvent qd je fais des boucles :)
Connectez-vous ou Inscrivez-vous pour répondre.