Garbage Collection ... eboueurs en greve
hdex
Membre
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
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
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
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.
en attendant le camion des poubelles ...
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)
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 ?
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 ?
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.
ç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 ...
(je sais, ce commentaire ne sert à rien )
Pourquoi casser toute une belle gestion de mémoire sur un logiciel existant pour utiliser ce truc ??
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
à‰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 ...
C'est une vieille manie d'informaticien, de toujours vouloir réparer quelque chose qui fonctionne
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 :
(requestVOIP retournant un objet de type NSData)
et bien en transformant ça en :
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
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...
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 ?
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 .