Garbage Collection ... eboueurs en greve

hdexhdex Membre
mars 2008 modifié dans API AppKit #1
Bonjour a tous,

Je suis en train de convertir mon appli a NSOperation et GC.
D'un cote ca fait plaisir de virer mes retain, autorelease et release et convertir les [pool release] en [pool drain] mais de l'autre j'ai des soucis de memoire.

Le premier truc que j'avais loupe et que meme si nsoperation simplifie le multi-thread, il ne faut pas oublier de creer un release pool dans la nouvelle thread.

Une fois cette premiere fuite identifie, j'ai continue a avoir des fuites (appli passe de 23-25 Mo dans activity monitor a plus de 100Mo le lendemain matin).

J'ai suppose que le garbage collector n'etait pas appele assez souvent, j'ai donc fait gaffe a mes [pool drain] et rajoute un [collector collectifneeded]. Ya du mieux mon appli monte seulement a 50Mo en une nuit ...

Je pensait que GC se debrouillait tout seul pour evaluer les besoins, est il possible que GC ne fasse pas le menage en memoire tant que cela n'est pas necessaire (plein de memoire dispo) ?

J'ai beau potasser la doc sur garbage collection, j'avoue etre perdu ...

note : j'ai trouve un bug de GC avec Core image (ah bah oui j'utilise) mais uniquement si on utlise des filtres Core image sur de la video (degradation de perf de 25% et GC ne fonctionnant pas correctement) ... donc je cherche toujours

Réponses

  • AliGatorAliGator Membre, Modérateur
    18:44 modifié #2
    Juste au passage pour dire que j'adore ton titre (ou plus exactement ton sous-titre)  :brule:

    Bon sinon tu es sûr d'avoir activé le GC ? Je j'ai pas Léopard et donc n'ai jamais testé l'Objective-C 2 et le GC, mais il me semblait qu'il y avait une option à  activer dans les configurations de compilation du projet pour qu'il active le GC (peut-être activé par défaut dans les nouveaux projets XCode... mais si tu dis convertir un ancien projet (créé avant l'avènement d'Obj-C 2.0 et de son GC?) où tu utilisais les NSReleasePools...)
  • helgrindhelgrind Membre
    18:44 modifié #3
    dans 1204589231:

    Bon sinon tu es sûr d'avoir activé le GC ? Je j'ai pas Léopard et donc n'ai jamais testé l'Objective-C 2 et le GC, mais il me semblait qu'il y avait une option à  activer dans les configurations de compilation du projet pour qu'il active le GC (peut-être activé par défaut dans les nouveaux projets XCode... mais si tu dis convertir un ancien projet (créé avant l'avènement d'Obj-C 2.0 et de son GC?) où tu utilisais les NSReleasePools...)


    Même dans les nouveaux projets il n'est pas activé par défaut.
  • hdexhdex Membre
    18:44 modifié #4
    Bon alors j'ai vérifié et j'ai bien payé la taxe d'enlèvement des ordures ménagères (Option de projets : GC required).

    en attendant le camion des poubelles ...
  • ClicCoolClicCool Membre
    18:44 modifié #5
    Salut Hdex

    N'aurais-tu pas, par hasard, utilisé dans ton projet un framework non prévu pour l'option GC required ?

    AppKit, Fondation et CoreData sont clean pour le GC
    Mais les autres pas forcément.
    Je me demande même si le WebKit l'est...


    P.S. As-tu des logs du genre "object ... has a non zéro retainCount"  ?
    (CFRetain par exemple, s'il est utilisé par un Framework à  l'insu de ton plein gré, peut provoquer ce genre de cafouilli il me semble)
  • hdexhdex Membre
    18:44 modifié #6
    Un framework non GC ?? fort possible.

    J'ai deja recompile Sparkle pour le mettre en mode GC sinon j'utilise AppKit et Foundation. J'ai aussi 2 #import lie a Quartz et Core Image (utilise uniquement pour modifie la couleur de mon icon dans le Dock via un filtre Core Image).

    Les pistes pour le moment :
    - j'ai rien compris a GC et le ramassage ne se fait que quand c'est neccessaire
    - un framework ne supporte pas le GC correctement (note : si un framework non-GC est inclus dans un projet GC, on se recoit un warning au moment de la compil)
    - certaines fonctions CF* sont utilises sans que je le sache

    J'ai aucun messages d'erreur en log et depuis mes ajouts de [pool drain] et [collector collectifneeded] l'utilisation de la memoire semble meilleur mais la tendance est a la hausse.

    Je suis en train de convertir des @property int valeurInt en @property (copy) NSInteger valeurInt, au cas ou ce serait ca qui utilise des fonctions CF* ...

    J'ai essaye d'identifier le probleme avec Zone Monitor mais j'avoue ne pas etre super balaise en decryptage d'addresse memoire  >:D >:D

    La question reste donc comment verifier que GC fonctionne et y a-t-il un moyen de debugger ?

  • Philippe49Philippe49 Membre
    18:44 modifié #7
    Ce post (non résolu) peut peut-être t'intéresser .
  • MalaMala Membre, Modérateur
    18:44 modifié #8
    A noter que dans mon cas, je n'active pas le GC. Donc il faut voir. D'après ce que décrit hdex, je n'ai pas l'impression qu'il ait de fuites si le GC est inactivé.
  • ClicCoolClicCool Membre
    18:44 modifié #9
    Si tu utilises CoreData peut-être est-ce aussi par là  qu'il faut explorer ?

    En particuliers le chapitre Reducing Memory Overhead.

    Sans oublier, si tes stores sont en SQLite, de peut-être vider leur cache de temps en temps ?
  • hdexhdex Membre
    18:44 modifié #10
    Merci pour les liens ...

    Je n'utilise pas Core Data ... du moins pas encore.

    Je n'avait effectivement pas de soucis avant d'activer GC, cela etant dit j'ai modifie pas mal de choses depuis (NSOperation, @property/@synthesize un peu partout, Sparkle recompile en mode GC).

    J'ai beau creer des releasepool la ou je fais des allocations memoires, j'ai toujours des fuites.

    Quand j'utilise la commande leaks, le nombre de leak est impressionant mais je ne sais pas si cet outil est valide avec GC.
    J'ai tente de debugger avec Zone Monitor et Instruments, sans grand succes pour le moment ... faut deja que j'arrive a comprendre ces 2 applis.

    Et moi qui pensait que GC allait me simplifier la vie ... j'en suis meme a me demander si je vais arreter les frais pour l'instant et retourner en mode retain/release.
  • ClicCoolClicCool Membre
    18:44 modifié #11
    dans 1204839870:

    .../... Et moi qui pensait que GC allait me simplifier la vie ... j'en suis meme a me demander si je vais arreter les frais pour l'instant et retourner en mode retain/release.


    ça c'est comme de penser que les bindings sont simples à  maà®triser sous prétexte qu'il y a moins de code à  taper  ;)
    (Y'a même des moments ou je pense encore qu'une approche "data source" est plus simple quoique fastidieuse)

    Entre utiliser une technique facile à  mettre en oeuvre et la maà®triser proprement, y'a tout un concept (souvent complexe) à  appréhender et une nouvelle logique à  assimiler ou même mieux à  s'approprier ...
  • schlumschlum Membre
    18:44 modifié #12
    Moi j'aime pas les GC  :P
    (je sais, ce commentaire ne sert à  rien  :o )

    Pourquoi casser toute une belle gestion de mémoire sur un logiciel existant pour utiliser ce truc ??  :'(
  • Philippe49Philippe49 Membre
    18:44 modifié #13
    dans 1204842867:

    ça c'est comme de penser que les bindings sont simples à  maà®triser sous prétexte qu'il y a moins de code à  taper  ;)
    (Y'a même des moments ou je pense encore qu'une approche "data source" est plus simple quoique fastidieuse)


    Entièrement d'accord.
    Dans toutes les sciences/techniques, la méthode "boà®te noire" ne simplifie que des situations standardisées, et elle complique les autres.
  • hdexhdex Membre
    18:44 modifié #14
    dans 1204866077:

    dans 1204842867:

    ça c'est comme de penser que les bindings sont simples à  maà®triser sous prétexte qu'il y a moins de code à  taper  ;)
    (Y'a même des moments ou je pense encore qu'une approche "data source" est plus simple quoique fastidieuse)


    Entièrement d'accord.
    Dans toutes les sciences/techniques, la méthode "boà®te noire" ne simplifie que des situations standardisées, et elle complique les autres.

    +1  .. je m'étais juste dit que partant d'une appli qui fonctionne sans probleme de memoire connue, les choses serait sinon simple du moins simplifié pour comprendre comment fonctionne GC.

    Pour l'instant l'histoire se resume a :
    - retain/release : C'est a toi de dire a la femme de menage ou et quand passe.
    - GC : La fée du logis ... mais comme toute bonne fée, tu sais pas vraiment quand elle est là  et comment elle fait  ;D



  • psychoh13psychoh13 Mothership Developer Membre
    18:44 modifié #15
    Peut-être tu peux essayer la méthode -collectExhaustively.
  • psychoh13psychoh13 Mothership Developer Membre
    18:44 modifié #16
    Au passage hdex, utiliser le mot clé "copy" dans la propriété d'un type scalaire n'a aucun intérêt. :D

    à‰crire ça : @property NSInteger valeurInt; suffit.
  • hdexhdex Membre
    18:44 modifié #17
    dans 1204909949:

    Au passage hdex, utiliser le mot clé "copy" dans la propriété d'un type scalaire n'a aucun intérêt. :D

    à‰crire ça : @property NSInteger valeurInt; suffit.


    Merci !! Effectivement "copy" ne sert à  rien pour un scalaire, on peut utiliser "assign" si l'on veut rester dans l'idée du @property parametre type nom ... ou carrement rien, ça marche aussi  :adios!:

    Dernière infos sur le GC, mon appli ne monte plus qu'à  30 Mo en une nuit (ça fait quand même presque 8Mo de fuites) simplement en ajoutant [NSApp setDelegate:self] dans awakefromNib (astuces glane sur macrumors)

    Si je ne trouve pas rapido, je pense que je vais retourner au mode classique et laisser GC mijoter dans mon neurone pour etre inclus seulement dans une nouvelle appli.
    Après tout pourquoi essayer de reparer quelque chose qui fonctionnait ...


  • AntilogAntilog Membre
    18:44 modifié #18
    dans 1204946685:


    Après tout pourquoi essayer de reparer quelque chose qui fonctionnait ...



    C'est une vieille manie d'informaticien, de toujours vouloir réparer quelque chose qui fonctionne
    :o
  • hdexhdex Membre
    18:44 modifié #19
    Les éboueurs sont passés !!!  :adios!: :adios!:
    Bon ils ont pas encore virés toutes les saloperies qui trainaient mais c'est déjà  pas mal.

    Mes fuites mémoires ont été divisées par 2 en faisant juste un petite manip.
    En fait j'ai l'habitude (bonne ou mauvaise à  vous de juger) d'écrire ce genre de code :
    NSData *requestResult =&nbsp; [requestVOIP startRequestOn:[voipIPAddressTextField stringValue] perform:defHDVoipParse];<br />
    

    (requestVOIP retournant un objet de type NSData)
    et bien en transformant ça en :
    NSData *requestResult = [[NSData alloc] init];<br />	requestResult = [requestVOIP startRequestOn:[voipIPAddressTextField stringValue] perform:defHDVoipParse];<br />
    

    Ca fuit beaucoup moins, j'ai commencé à  "convertir" mon code et les résultat sont encourageants.

    C'est comme ci le alloc init permettait à  GC de bien conserver une trace de l'objet.
    En creusant un peu l'utilisation de Instruments, j'ai découvert que l'on pouvait tracer l'origine des fuites et faire des comparaisons entre plusieurs executions (c'est comme ça que j'ai vu que mes fuites était maintenant 2 fois moindre)

    Il faut donc que je me mette à  coder un peu plus propre et utliser Instruments un peu plus (ajouter un grain de patience si vous faites tourner Instruments sur un Tibook 867Mhz ou même un Mac mini PPC 1.42GHz comme moi)

    Encore merci à  tous pour les pistes, liens et idées ... allez c'est ma tournée  :p   :p
  • psychoh13psychoh13 Mothership Developer Membre
    18:44 modifié #20
    Euh, je dois dire que c'est assez surprenant...
    En temps normal, t'as deuxième écriture se traduit par une grosse fuite de mémoire... Parce que tu alloues de la mémoire par alloc/init et immédiatement après tu remplaces la référence par une autre...

    Ce qui fait que tes poubelles sont deux fois plus pleines qu'avant...
  • Philippe49Philippe49 Membre
    18:44 modifié #21

    N'est-ce pas ici un nettoyage "if necessary" ?

    La double allocation forçant en quelque sorte le Garbage Collector à  s'occuper de notre instance, plutôt que de ne pas la voir parce qu'après tout il reste encore de la place ?
  • psychoh13psychoh13 Mothership Developer Membre
    18:44 modifié #22
    Bah ouais c'est ça ma crainte... Et qui me renforce ma conviction que les garbage collector sont à  chier... C'est parce que les poubelles débordent de partout que l'armée s'en occupe...
  • hdexhdex Membre
    18:44 modifié #23
    Bon un coup ca fuit, un coup ca fuit plus ... bref chuis paume.  :crackboom:-

    Soit j'ai rien compris au planning des eboueurs (aka Garbage Collection Programming Guide) ce qui est probable, soit le GC est un peu touchy a manier.


    Bref, de toutes mes experimentations je garde NSOperation et les @property/@synthesize mais GC part a la poubelle pour le moment  >:) .
  • psychoh13psychoh13 Mothership Developer Membre
    18:44 modifié #24
    Bonne résolution. Je pense que le GC n'est pas encore mature... Et puis c'est à  chier à  la base donc... :D
Connectez-vous ou Inscrivez-vous pour répondre.