Gestion mémoire à  la mano, Autorelease pool, Garbage Collector. Votre sentiment?

MalaMala Membre, Modérateur
09:52 modifié dans Actualités #1
dans 1182336841:

je trouve que l'autorelease pool est une des pires idées de Foundation. Pour ceux qui trouvent que c'est en contradiction avec mon affirmation précédente sur les GC, voici l'explication: l'autorelease pool pour moi est un travail à  moitié fait: ou on fait du full manuel, ou on fait de l'automatique complet et on le fait au bon moment (c'est à  dire au moment des allocations). L'autorelease pool, ce n'est rien d'autre que "reporter" un problème.

Aller histoire de pas encore partir en live (comme à  mon habitude :)) sur le sujet "Apprentissage des langages", j'ouvre un autre sujet.

Perso, je trouve justement très pratique le fait de pouvoir choisir entre autorelease pool ou gestion à  la mano. Si la plupart du temps j'ai une grosse préférence pour une gestion fine de la mémoire, l'autorelease pool permet de répondre à  des situations qui seraient parfois complexes lorsqu'on doit partager des objets.

Pour une gestion des libérations au moment des allocations avec un GC, j'ai du mal a voir l'intérêt. A la création de chaque objet le GC ferait le ménage? Mais que ce passe-t-il si on a des threads en parallèle qui allouent et libèrent? A chaque allocation le GC ferait un tour de piste? J'ai du mal a croire que cela apporterait un gain.

Toujours est-il que j'aimerais bien en savoir un peu plus sur le fonctionnement du Garbage Collector de Leopard. Quelqu'un a des infos techniques sur son fonctionnement?

Réponses

  • schlumschlum Membre
    juin 2007 modifié #2
    Je trouve que l'AutoReleasePool est une gestion assez fine de la mémoire qui résout les casse-têtes qu'on a en C++ qu'on est souvent obligé de résoudre par callbacks...
    Dans l'absolu, l'AutoReleasePool n'est qu'un array qui pose un retain sur l'objet "auto-releasé" et le relâche quand il est relâché lui même. C'est suffisamment propre et efficace, non ?  ???

    [Edit] Le GC par contre, beuh...
  • juin 2007 modifié #3
    Le truc justement, c'est qu'à  mes yeux, on n'a justement pas le choix: il faut éviter autant que possible son usage (au risque d'avoir des pics de conso mémoire et processeur) et lorsque qu'on est dans certaines situations (mais dont le nombre est assez limité), il faut l'utiliser. Donc ce n'est pas un choix où on choisit l'un ou l'autre suivant son bon vouloir, mais un choix tranché déterminé par les circonstances.

    Bon évidemment, pour des opérations non critiques, on ne voit pas la différence, mais du coup on prend des sales habitudes pour des opérations critiques. On bien alors on oublie qu'on a implémenté une méthode pour un usage non critique, puis quelques mois après on la réutilise dans une opération critique et là  pouf bonjour la conso mémoire.

    dans 1182347378:
    C'est suffisamment propre et efficace, non ?  ???


    Oui c'est propre, mais mal utilisé ça donne lieu à  des "abus" qui peuvent parfois se glisser de manière très subtile. Et je n'aime pas les trucs qui permettent trop facilement les "abus".
  • BruBru Membre
    09:52 modifié #4
    dans 1182347378:

    Je trouve que l'AutoReleasePool est une gestion assez fine de la mémoire qui résout les casse-têtes qu'on a en C++ qu'on est souvent obligé de résoudre par callbacks...
    Dans l'absolu, l'AutoReleasePool n'est qu'un array qui pose un retain sur l'objet "auto-releasé" et le relâche quand il est relâché lui même. C'est suffisamment propre et efficace, non ?  ???


    Je plussoies, comme on dirait sur le site fétiche de Schlum.

    L'autoreleasepool n'est certes pas la panacée (mais, en POO, la problématique de la gestion de la mémoire est le point noir de cette pratique), mais représente un bon compromis entre garbage-collector (on rien n'est maitrisé par le programmeur) et gestion manuelle à  la C++, où le moindre leak devient fatal à  l'appli (qui ne connait pas les fameux "vc runtime corruption" sur windows...).

    Juste au sujet du GC : actuellement, je développe au boulot un portail d'entreprise basé sur des portlets (écrits en Java)...
    Ces portlets sont amenés à  gérer des volumes d'objets conséquents.
    Parfois, le portail se bloque (pendant quelques secondes) : ceci est dû au GC qui se lance, locke des portions de mémoire pour les nettoyer, ce qui gèle les autres process situés dans les mêmes zones mémoire.
    La parade ? Dès qu'un objet n'est plus utilisé, il faut absolument mettre sa référence à  null. Bref, ça ressemble furieusement à  un release, un free, ou a un delete.0

    .
  • schlumschlum Membre
    09:52 modifié #5
    dans 1182348413:

    Le truc justement, c'est qu'à  mes yeux, on n'a justement pas le choix: il faut éviter autant que possible son usage (au risque d'avoir des pics de conso mémoire et processeur) et lorsque qu'on est dans certaines situations (mais dont le nombre est assez limité), il faut l'utiliser. Donc ce n'est pas un choix où on choisit l'un ou l'autre suivant son bon vouloir, mais un choix tranché déterminé par les circonstances.


    Quand tu dis "il faut l'utiliser", ce n'est pas vraiment exact ; c'est plutôt "il est pratique de l'utiliser". Car quand on l'utilise, c'est en général pour se sortir d'une situation qui demanderait une gestion par Callback dans d'autres langage (C++ par exemple).
    Là  je suis sur un gros projet avec beaucoup de C++ (sur Mac  :P) et les callbacks, c'est pas toujours la joie... Quand il faut se trimballer plusieurs paramètres dont on a besoin en plus, ça devient rapidement illisible sans un minimum d'organisation. En Objective-C, j'ai très rarement eu besoin de callback de ce type grâce justement à  l'AutoReleasePool   o:)
    À noter que la désallocation mémoire n'est quand même pas CPUphage à  ce point... Ou alors c'est qu'il y a vraiment beaucoup d'objets dans ton pool  ???

    Bon évidemment, pour des opérations non critiques, on ne voit pas la différence, mais du coup on prend des sales habitudes pour des opérations critiques. On bien alors on oublie qu'on a implémenté une méthode pour un usage non critique, puis quelques mois après on la réutilise dans une opération critique et là  pouf bonjour la conso mémoire.


    Le Garbage Collector est pire sur ce point... Car rien n'est maà®trisé contrairement aux AutoReleasePool dont on sait exactement le moment de la destruction (entre chaque cycle de runloop du thread principal par exemple).

    dans 1182347378:
    C'est suffisamment propre et efficace, non ?  ???


    Oui c'est propre, mais mal utilisé ça donne lieu à  des "abus" qui peuvent parfois se glisser de manière très subtile. Et je n'aime pas les trucs qui permettent trop facilement les "abus".


    Ah... Beaucoup de choses dans le monde la programmation permet facilement des abus !  :-\\ À nous de ne pas les commettre  :adios!:
  • 09:52 modifié #6
    dans 1182349341:
    Quand tu dis "il faut l'utiliser", ce n'est pas vraiment exact ; c'est plutôt "il est pratique de l'utiliser".

    Non non, il y a des cas où il faut l'utiliser (les validations par KVC par exemple, c'est écrit texto dans la doc). Mais sinon comme je programme avec Cocoa, je suis les conventions de Cocoa qui ont pour moi "force de loi".

    dans 1182349341:
    Ah... Beaucoup de choses dans le monde la programmation permet facilement des abus !  :-\\ À nous de ne pas les commettre  :adios!:

    Yep, mais là  c'est vicieux et parfois le truc qu'on fait de manière "temporaire" devient "temporairement définitif" (à  qui ça n'est jamais arrivé?) et après on passe beaucoup de temps à  repérer les fuites. Donc j'ai pris une position radicale pour éviter les fuite: l'autorelease pool c'est mal (mais un mal nécessaire).
  • schlumschlum Membre
    juin 2007 modifié #7
    Oui, c'est sûr, avec les constructeurs de commodité (dont il n'y a parfois pas d'équivalent en constructeur classique ; avec QTMovie par exemple, il me semble) et les KVC (je n'utilise pas, donc je n'ai pas d'idée sur la question), il y a des cas où il faut l'utiliser...

    Cependant, on peut limiter largement la portée en définissant son propre AutoReleasePool à  un endroit donné  ;) (et de cette façon, décider exactement quand il est adéquat de relâcher les objets placés dedans).

    [Edit] Désolé Mala, avec tout ça, on oublie les questions techniques que tu posais à  propos du GC :) (perso, aucune idée...)
  • MalaMala Membre, Modérateur
    09:52 modifié #8
    Concernant C++, j'ai souvenir d'avoir utilisé à  une époque des "Smart Pointer" pour un gros projet partageant de nombreuses ressources. Pour plus d'infos... Smart Pointer
  • schlumschlum Membre
    09:52 modifié #9
    Ouais, mais j'aime pas  ;D (comme tout ce qui touche de près ou de loin aux templates...)

    C'est quand même vachement "bidouille complexe"... :(
  • AliGatorAliGator Membre, Modérateur
    09:52 modifié #10
    dans 1182350673:
    Mais sinon comme je programme avec Cocoa, je suis les conventions de Cocoa qui ont pour moi "force de loi".
    C'est là  où l'on rejoint l'autre sujet splitté depuis, à  savoir l'impact des langages appris au cours de ton cursus de programmeur (au cours des études ou des progs persos) :
    - Toi Renaud à  te lire tu ne jures que par Obj-C et Cocoa. Je ne t'en blame pas, je suis plutôt fan aussi de pas mal de concepts de ce langage+framework :P
    - Mais la grande différence que je vois avec schlum (ou moi) c'est qu'on a rencontré des problématiques dans d'autres langages (entre autres la gestion de mémoire), comme par exemple en C la nécessité parfois de faire des callbacks pour demander de libérer la mémoire qd nécessaire, ou de faire notre propre système de reference counting, ou autre...

    ... du coup à  en être passé par là  et à  voir la galère que c'est, quel bonheur de trouver un truc comme les AutoReleasePool !! Je dis pas que c'est une solution parfaite, mais ça facilite énormément la vie... tout en laissant quand même au programmeur le soin de pas coder "bêtement sans réfléchir à  la gestion mémoire" mais en ayant toujours de quoi maitriser la mémoire (de façon 100x plus aisée).
  • juin 2007 modifié #11
    Non. Contrairement à  schlum ou toi ou Mala j'ai commencé avec des langages à  gestion de mémoire automatique et je n'ai jamais eu de cours de "bas niveau". Donc on part de points de vue radicalement opposés. Ce que vous voyez comme une simplification, moi je le vois comme un risque de traiter une AP comme un GC, alors qu'au niveau du fonctionnement ce sont 2 choses radicalement différentes. Dans l'exemple donné par Bru, avec une AP remettre un pointeur à  nil n'a pas d'effet sur les performances, alors qu'avec un GC oui.

    Donc pour une personne qui a ce background, présenter l'autorelease pool comme "un choix" est une grosse erreur pédagogique: il ira intuitivement vers la solution vers laquelle il est le plus à  l'aise (ou la solution de moindre effort). Or comme je l'ai dit plus haut, pour moi, il n'y a pas de choix. Il y a des circonstances précises comme celles que vous mentionnez où son utilisation est vraiment simplificatrice donc utile, mais le reste du temps utiliser l'autorelease pool n'est pas "équivalent" à  ne pas l'utiliser. Bon évidemment, dans la mesure où la plus grosse partie du code n'est pas critique, on pourrait écrire ces portions dans un langage interprété qu'on ne verrait pas la différence.

    dans 1182351031:

    Cependant, on peut limiter largement la portée en définissant son propre AutoReleasePool à  un endroit donné  ;) (et de cette façon, décider exactement quand il est adéquat de relâcher les objets placés dedans).


    Bien sûr et tu dis ça à  un gars qui n'a pas un background de "professionnel" (en combinant ça avec un "tu as le choix", c'est encore mieux), il va te sortir des:

    [tt]NSString *str;
    NSAutoreleasePool *pool;
    for ( i = 0 ; i < 100000 ; i++ ) {
    pool = [NSAutoreleasePool new];
    str = [NSString string];

    [pool release];
    }[/tt]

    Suis pas sur que ce soit la meilleure idée.

    Parce que bon, même si cette solution de créer des pool additionnels résoud des problèmes, le risque que je vois pour quelqu'un qui a un background "obscur" est qu'il se dise "oh, de toute façon je peux créer des pools" et que donc il se mette à  utiliser des objets autoreleasés dans les implémentations de ses méthodes alors que ça doit être évité.

    dans 1182358760:
    C'est là  où l'on rejoint l'autre sujet splitté depuis, à  savoir l'impact des langages appris au cours de ton cursus de programmeur (au cours des études ou des progs persos)

    C'est surtout là  qu'on se rend compte qu'une communication non adaptée son interlocuteur mène à  un résultat qu'on déplore par la suite.
  • schlumschlum Membre
    09:52 modifié #12
    En fait, je pense que les AutoReleasePool font complètement partie de la philosophie Objective-C. Une manière de penser en terme de gestion mémoire qui ne se trouve que (?) dans ce langage.
    Il faut composer avec, sans bien sûr en abuser !

    Je ne pense pas que ça soit un "choix", mais que certaines situations amènent à  l'utiliser naturellement, tandis que la plupart des situations permettent de l'éviter.
  • MalaMala Membre, Modérateur
    09:52 modifié #13
    Je trouve que vu sous cet angle, les arguments de Renaud se tiennent.
  • AliGatorAliGator Membre, Modérateur
    09:52 modifié #14
    C'est pour ça que je disais aussi : "Je dis pas que les Autorelease Pool c'est la solution parfaite/miracle" mais juste "c'est quand même vachement pratique dans certains cas par rapport aux blocages que l'on peut rencontrer dans d'autres langages et qui sont bien plus source de prises de tête".

    Donc en résumé tant qu'on peut tout gérer à  la main (faire des objets non auto-releasés mais les releaser dès que possible), c'est mieux de le faire, mais ça tout ceux qui ont fait du C++ le savent déjà  (dès qu'on fait un new, faut penser à  faire le delete dès qu'on se sert plus de l'objet), et pour les cas où c'est bien plus prise de tête et que ce n'est pas aussi simple, là  où en C++ on ne pouvait pas non plus faire un delete immédiat et on était bloqué (donc on passait par des patterns un peu bizarres genre callback de demande de delete), en Cocoa on a l'outil "autorelease".

    C'est pour ça qu'à  mon sens ceux qui ont suivi un cursus genre C, puis C++, puis Cocoa, ne tomberont pas dans le panneau du "autoreleasepool à  toutes les sauces" (ni du GC à  toutes les sauces). Ceux qui ont fait du java mais pas de C/C++ seront fan du GC (et de l'autoreleasepool avant ObjC-2.0 à  défaut de GC)...

    Ca dépend comment on a appris à  apprendre et à  appréhender la mémoire dans les divers langages qu'on a touché. (Et c'est pour ça que je suis pas fan du tout-Java côté enseignement non plus, où tu te poses pas de questions et tu laisses bosser le GC sans réfléchir sur les pb de mémoire)

    Conclusion, les 3 solutions (release, autorelease, GC) se tiennent et ne sont pas concurrentes mais complémentaires si utilisées à  bon escient.
  • MalaMala Membre, Modérateur
    09:52 modifié #15
    Et vu sous cet angle, les arguments d'Ali se tiennent.  :P

    dans 1182422974:

    C'est pour ça qu'à  mon sens ceux qui ont suivi un cursus genre C, puis C++, puis Cocoa, ne tomberont pas dans le panneau du "autoreleasepool à  toutes les sauces" (ni du GC à  toutes les sauces). Ceux qui ont fait du java mais pas de C/C++ seront fan du GC (et de l'autoreleasepool avant ObjC-2.0 à  défaut de GC)...

    C'est effectivement très intéressant de voir comme on en revient à  l'impact de l'apprentissage initial.
  • schlumschlum Membre
    juin 2007 modifié #16
    Moi aussi je suis d'accord avec ses arguments comme quoi il peut y avoir de l'abus de la part de programmeurs formés au Garbage Collector !
    Là  où je ne suis pas d'accord, c'est pour le "je trouve que l'autorelease pool est une des pires idées de Foundation"  ;)
    (et j'ai dit longuement au dessus pourquoi)


    Pour moi, la pire idée dans Foundation va venir avec l'ObjectiveC 2.0
    Il y en aura même deux :
    - Le Garbage Collector
    - La possibilité d'accéder directement aux paramètres d'une classe avec "." (qui remet complètement en cause la philosophie de l'encapsulation et risque de causer des troubles dans les esprits des programmeurs venant du C et pour qui "." veut dire "struct")
  • juin 2007 modifié #17
    dans 1182425895:
    Là  où je ne suis pas d'accord, c'est pour le "je trouve que l'autorelease pool est une des pires idées de Foundation"  ;)


    Faut aussi dire que le Renaud il a aussi tendance à  "trolliser" des discussions qui peuvent être intéressantes en utilisant des phrases au superlatif dans ce genre, mais qui sont évidemment exagérées.

    Maintenant en matière de troll, je dois encore faire des progrès. Celui là  a donné lieu à  une discussion intéressante, alors que normalement ça doit donner lieu à  une discussion stérile.
  • schlumschlum Membre
    09:52 modifié #18
    dans 1182427547:
    Maintenant en matière de troll, je dois encore faire des progrès. Celui là  a donné lieu à  une discussion intéressante, alors que normalement ça doit donner lieu à  une discussion stérile.


    Oui 
  • psychoh13psychoh13 Mothership Developer Membre
    octobre 2007 modifié #19
    dans 1192876862:
    Je maintiens qu'il vaut mieux utiliser :
    NSString *str = [[NSString alloc] initWithString:@&quot;test&quot;];<br />// ... Travail avec str<br />[str release];
    


    Que :
    NSString *str = [NSString stringWithString:@&quot;test&quot;];<br />// ... Travail avec str
    


    C'est plus lisible et plus efficace :P


    Personnellement, je maintiens au contraire que si la durée de vie de l'objet est limité à  la méthode, il vaut mieux utiliser les méthodes de convenances, parce que si tu crées 15 objets qui ne vivront pas au-delà  de la méthode, faire 15 releases augmentent inutilement la taille du code. Et quand tes méthodes font 200 lignes t'es content de pouvoir te passer de la recherche des objets à  supprimer à  la fin. :D Enfin de toutes façons, il faut toujours faire attention à  ce qu'on fait, qu'on utilise les releases ou les autoreleases.
  • schlumschlum Membre
    09:52 modifié #20
    Là  où les AutoReleasePool sont une très bonne chose, c'est qu'ils fonctionnent comme les Smart Resources C++

    This behavior has implications for exceptional conditions. If an exception occurs, and the thread suddenly transfers out of the current context, the pool associated with that context is released. However, if that pool is not the top pool on the thread's stack, all the pools above the released pool are also released (releasing all their objects in the process). The top autorelease pool on the thread's stack then becomes the pool previously underneath the released pool associated with the exceptional condition. Because of this behavior, exception handlers do not need to release objects that were sent autorelease. Neither is it necessary or even desirable for an exception handler to send release to its autorelease pool, unless the handler is re-raising the exception.


    En gros, si une exception est envoyée avant le "release" du pool, et que cette exception est catchée au dessus (c'est le cas si l'exception se produit dans une fonction exécutée par un NSTimer par exemple), il n'y a pas leak, l'AutoReleasePool est détruit quand même !
  • psychoh13psychoh13 Mothership Developer Membre
    09:52 modifié #21
    Conclusion : c'est quand même pratique les autorelease pools.  :o :P  ;D
  • schlumschlum Membre
    09:52 modifié #22
    Ah oui, je suis absolument fan aussi !
    Mais pas pour l'utiliser dès que possible  :P
    C'est quand même déléguer sa gestion mémoire à  un objet relativement opaque (qui fait effectivement ça très bien à  priori !), et je préfère garder la main sur ce que je peux.
Connectez-vous ou Inscrivez-vous pour répondre.