Création de grandes strings

Eric P.Eric P. Membre
07:21 modifié dans API UIKit #1
Bonjour,

Dans iPocket Draw, j'envoie les dessins par mail sous forme de fichier texte dans le corps du message.
Ca fonctionne mais seulement avec peu d'objets surtout en DXF.
Je voie avec Instruments que pour générer un fichier texte final de 32 Ko j'ai un pic d'occupation mémoire de 22 Mo (dans le simulateur) !
Et sur mon iPhone ça coince avec un gros crash...
Je construit le fichier texte avec plein de monTexte = [monTexte stringByAppendingString:@xxxx\n];
Je soupçonne que cela n'est pas la meilleure solution vu le résultat.
Des avis éclairés me seraient bd'un grand secours.

Merci

Eric

Réponses

  • Philippe49Philippe49 Membre
    mai 2009 modifié #2
    En forçant "le nettoyage" cela améliore peut être ?

    Boucle
    {
    NSAutoreleasePool * pool=[[NSAutoreleasePool alloc] init];
    Boucle
    monTexte=[monTexte stringByAppendingString:@xxxx\n];
    Fin de Boucle
    // retain sur ce qui doit l'être (schlum addendum)
    [pool release];
    }
    Fin de Boucle

    Dans ce schéma, les strings créées sont éliminées plus rapidement, au détriment sans doute de la rapidité. Là  il faut arbitrer rapidité/empreinte mémoire
  • schlumschlum Membre
    07:21 modifié #3
    dans 1241285691:

    Je construit le fichier texte avec plein de monTexte = [monTexte stringByAppendingString:@xxxx\n];
    Je soupçonne que cela n'est pas la meilleure solution vu le résultat.
    Des avis éclairés me seraient bd'un grand secours.


    C'est pas malin du tout comme technique... À chaque fois ça met un nouvel objet NSString dans la mémoire "autoreleased" qui n'est libérée qu'une fois par passage dans la runloop.

    Pourquoi ne pas utiliser un NSMutableString et faire des "appendString" sur le même à  chaque fois ?
  • schlumschlum Membre
    mai 2009 modifié #4
    dans 1241287602:

    En forçant "le nettoyage" cela améliore peut être ?

    Boucle
    {
    NSAutoreleasePool * pool=[[NSAutoreleasePool alloc] init];
    Boucle
    monTexte=[monTexte stringByAppendingString:@xxxx\n];
    Fin de Boucle
    [pool release];
    }
    Fin de Boucle

    Dans ce schéma, les strings créées sont éliminées plus rapidement, au détriment sans doute de la rapidité. Là  il faut arbitrer rapidité/empreinte mémoire


    T'as pas oublié un "retain" quelque-part dans ta technique ?  :)
    Parce que là  t'as plus rien du tout après ton "pool release", "monTexte" pointe sur un objet inexistant.
  • Philippe49Philippe49 Membre
    07:21 modifié #5
    dans 1241319173:

    T'as pas oublié un "retain" quelque-part dans ta technique ?  :)

    Si après la première boucle, je donnais un schéma, pas du code.

    Le côté intéressant de la question était pour moi était dans le problème de la gestion de beaucoup d'instances intermédiaires, et comment faire pour s'en débarasser. D'où la méthode proposée.
    Mais je confirme la grande sagesse de Schlum, Eric, utilise une NSMutableString sans créer d'instance intermédiaire. Et si tu es obligé de créer des instances intermédiaires, utilise la technique de l'autorelease pool.
  • Eric P.Eric P. Membre
    07:21 modifié #6
    Merci pour vos réponses.
    Je teste ça dans la journée et je vous dirais le gain (en mémoire) réalisé.

    Mais je dois avouer que je n'ai pas bien compris la différence entre NSString et NSMutableString.
    En relisant la doc., c'est vrai que NSMutableString a des méthodes intéressantes, genre appendstring qui est tout à  fait ce qui me faut.
    Et effectivement si à  chaque "monTexte=[monTexte stringByAppendingString:@xxxx\n];" cela crée une nouvelle NSSTring, je devais en avoir un tas...et de taille croissante en plus.

    A plus tard.

    Eric
  • Philippe49Philippe49 Membre
    07:21 modifié #7
    NSString = chaà®ne de longueur et de contenu constant
    NSMutableString = chaà®ne de longueur variable, et de contenu variable

    Par derrière, Foundation doit faire du hachage à  ta place pour les NSMutableString, alors que pour NSString il réagit en fonction de la longueur de la chaà®ne.
  • Eric P.Eric P. Membre
    07:21 modifié #8
    Whoua !

    Le résultat est très impressionnant.
    Avec les "monTexte=[monTexte stringByAppendingString:@xxxx\n];" je passais d'environ 740 Ko à  un pic à  22 Mo.
    Avec les NSMutableString et appendstring, je monte, pour créer le même fichier, à  825 Ko !!!

    Bonne journée à  tous.

    Eric
  • schlumschlum Membre
    mai 2009 modifié #9
    dans 1241333826:
    Le côté intéressant de la question était pour moi était dans le problème de la gestion de beaucoup d'instances intermédiaires, et comment faire pour s'en débarasser. D'où la méthode proposée.


    Tout à  fait, quand on utilise beaucoup les objets "autoreleased", il faut gérer des pools dans les "scopes" intermédiaires...
    C'est très bien expliqué ici :
    http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html

    C'est encore plus vrai sur les plate-formes embarquées très sensibles à  la mémoire résiduelle.
  • schlumschlum Membre
    07:21 modifié #10
    dans 1241337460:

    Whoua !

    Le résultat est très impressionnant.
    Avec les "monTexte=[monTexte stringByAppendingString:@xxxx\n];" je passais d'environ 740 Ko à  un pic à  22 Mo.
    Avec les NSMutableString et appendstring, je monte, pour créer le même fichier, à  825 Ko !!!

    Bonne journée à  tous.

    Eric


    C'est normal, tu n'utilises pas du tout le pool d'"autorelease" et d'objets temporaires, donc tu consommes pile poil la mémoire qu'il faut (peut-être à  un chouilla près, je ne sais pas comment NSMutableString gère ses allocations en interne).
    En plus, ça doit être plus rapide, car largement plus optimisé.
  • Eric P.Eric P. Membre
    07:21 modifié #11
    Pour les performances, je ne peux pas confirmer car sur mon iPhone la version précédente bloquait et sur le simulateur, cela était rapide malgré la mauvaise gestion de la mémoire.

    Encore merci.

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