Comment fonctionne le nouveau mécanisme de comptage automatique des références?

206

Quelqu'un peut-il m'expliquer brièvement comment fonctionne l'ARC? Je sais que c'est différent de Garbage Collection, mais je me demandais exactement comment cela fonctionnait.

De plus, si ARC fait ce que fait GC sans entraver les performances, alors pourquoi Java utilise-t-il GC? Pourquoi n'utilise-t-il pas également ARC?

user635064
la source
2
Cela vous dira tout à ce sujet: http://clang.llvm.org/docs/AutomaticReferenceCounting.html La façon dont il est implémenté dans Xcode et iOS 5 est sous NDA.
Morten Fast
14
@mbehan C'est un mauvais conseil. Je ne veux pas me connecter ou même avoir un compte pour le centre de développement iOS, mais je suis néanmoins intéressé à en savoir plus sur ARC.
Andres F.
1
ARC ne fait pas tout ce que GC fait, il vous oblige à travailler explicitement avec la sémantique de référence forte et faible, et fuit la mémoire si vous ne les obtenez pas correctement. D'après mon expérience, cela est d'abord délicat lorsque vous utilisez des blocs dans Objective-C, et même après avoir appris les astuces, vous vous retrouvez avec un code passe-partout ennuyeux (IMO) autour de nombreuses utilisations des blocs. Il est plus pratique d'oublier les références fortes / faibles. De plus, GC peut fonctionner un peu mieux que ARC wrt. CPU, mais nécessite plus de mémoire. Cela peut être plus rapide que la gestion de mémoire explicite lorsque vous avez beaucoup de mémoire.
TaylanUB le
@TaylanUB: "nécessite plus de mémoire". Beaucoup de gens le disent mais j'ai du mal à y croire.
Jon Harrop
2
@ JonHarrop: Actuellement, je ne me souviens même pas pourquoi j'ai dit cela, pour être honnête. :-) En attendant, je me suis rendu compte qu'il existe tellement de stratégies GC différentes que de telles déclarations générales sont probablement sans valeur. Permettez-moi de réciter Hans Boehm de ses mythes et demi-vérités d'allocation de mémoire : "Pourquoi cette région est-elle si sujette aux sagesses populaires?"
TaylanUB

Réponses:

244

Chaque nouveau développeur qui vient à Objective-C doit apprendre les règles rigides de la conservation, de la libération et de la libération automatique des objets. Ces règles spécifient même des conventions de dénomination qui impliquent le nombre de rétention d'objets renvoyés par les méthodes. La gestion de la mémoire dans Objective-C devient une seconde nature une fois que vous prenez ces règles à cœur et les appliquez de manière cohérente, mais même les développeurs Cocoa les plus expérimentés glissent de temps en temps.

Avec l'analyseur statique Clang, les développeurs LLVM ont réalisé que ces règles étaient suffisamment fiables pour pouvoir construire un outil pour signaler les fuites de mémoire et les libérations excessives dans les chemins empruntés par votre code.

Le comptage automatique des références (ARC) est la prochaine étape logique. Si le compilateur peut reconnaître où vous devez conserver et libérer des objets, pourquoi ne pas lui faire insérer ce code pour vous? Les tâches rigides et répétitives sont ce que les compilateurs et leurs frères sont grands. Les humains oublient des choses et font des erreurs, mais les ordinateurs sont beaucoup plus cohérents.

Cependant, cela ne vous libère pas complètement du souci de la gestion de la mémoire sur ces plateformes. Je décris le problème principal à surveiller (conserver les cycles) dans ma réponse ici , qui peut nécessiter un peu de réflexion de votre part pour marquer les pointeurs faibles. Cependant, c'est mineur par rapport à ce que vous gagnez dans ARC.

Par rapport à la gestion manuelle de la mémoire et à la récupération de place, ARC vous offre le meilleur des deux mondes en supprimant la nécessité d'écrire du code de conservation / libération, sans pour autant avoir les profils de mémoire d'arrêt et en dents de scie vus dans un environnement de récupération de place. Les seuls avantages de la récupération de place par rapport à cela sont sa capacité à gérer les cycles de rétention et le fait que les affectations de propriétés atomiques sont peu coûteuses (comme expliqué ici ). Je sais que je remplace tout mon code Mac GC existant par des implémentations ARC.

Quant à savoir si cela pourrait être étendu à d'autres langues, il semble axé sur le système de comptage des références dans Objective-C. Il pourrait être difficile de l'appliquer à Java ou à d'autres langages, mais je ne connais pas suffisamment les détails du compilateur de bas niveau pour y faire une déclaration définitive. Étant donné qu'Apple est celui qui pousse cet effort dans LLVM, Objective-C passera en premier, à moins qu'une autre partie n'engage des ressources importantes pour cela.

Le dévoilement de ces développeurs choqués à la WWDC, donc les gens ne savaient pas que quelque chose comme ça pouvait être fait. Il peut apparaître sur d'autres plates-formes au fil du temps, mais pour l'instant, il est exclusif à LLVM et Objective-C.

Brad Larson
la source
56
c'est moi qui souligne: cela ne vous libère pas complètement de la gestion de la mémoire
bshirley
6
L'ARC est-elle vraiment une innovation? D'après votre réponse, je conclus que l'ARC est un nouveau concept, qui est utilisé pour la première fois dans Objective-C (corrigez-moi si je me trompe). Pour être honnête, je ne suis pas un développeur Objective-C et je ne connais pas grand-chose à ARC, mais Boost Shared Pointers (voir boost.org) n'est-il pas exactement la même chose? Et s'ils ne le sont pas, quelle est la différence?
theDmi
2
@DMM - Plutôt que de compter sur des opérateurs surchargés (comme le fait Boost), il s'agit d'un processus au niveau du compilateur, qui l'étend à l'ensemble du langage. Entre autres choses, cela facilite la conversion d'une application comptée manuellement par référence en ARC. Boost peut également gérer les variables locales différemment d'ARC, où ARC sait au moment où une variable locale n'est plus utilisée et peut se libérer à ce moment-là. Je crois qu'avec Boost, vous devez toujours spécifier en quelque sorte que vous avez terminé avec la variable.
Brad Larson
6
Pour répondre à la question "est-ce nouveau", Delphi dispose d'un comptage automatique des références pour les chaînes, les tableaux et les interfaces (pour la prise en charge COM) depuis plus d'une décennie. Je suis d'accord que c'est vraiment un bon compromis entre un environnement gc'd et un environnement "tout faire manuellement". Je suis content que ce soit dans ObjC et LLVM (donc d'autres langages peuvent également en profiter).
davidmw
2
@theDmi: "L'ARC est-elle vraiment une innovation?". Le comptage automatique des références a été inventé en 1960 et a été utilisé dans de nombreux langages tels que Python et Mathematica. Il n'est pas utilisé dans la JVM ou le CLR car il est très lent et fuit des cycles.
Jon Harrop
25

ARC est juste un ancien jeu de retenue / libération (MRC) avec le compilateur qui détermine quand appeler la conservation / libération. Il aura tendance à avoir des performances plus élevées, une utilisation maximale de la mémoire de pointe et des performances plus prévisibles qu'un système GC.

En revanche, certains types de structure de données ne sont pas possibles avec ARC (ou MRC), tandis que GC peut les gérer.

Par exemple, si vous avez une classe nommée node et que node a un NSArray d'enfants et une seule référence à son parent qui "fonctionne" avec GC. Avec ARC (et le comptage manuel des références également), vous avez un problème. Tout nœud donné sera référencé à partir de ses enfants et également de son parent.

Comme:

A -> [B1, B2, B3]
B1 -> A, B2 -> A, B3 -> A

Tout va bien lorsque vous utilisez A (disons via une variable locale).

Lorsque vous en aurez terminé (et B1 / B2 / B3), un système GC décidera éventuellement de regarder tout ce qu'il peut trouver à partir de la pile et des registres CPU. Il ne trouvera jamais A, B1, B2, B3, il les finalisera donc et recyclera la mémoire en d'autres objets.

Lorsque vous utilisez ARC ou MRC et que vous finissez avec A, il a un décompte de 3 (B1, B2 et B3 le référencent tous), et B1 / B2 / B3 aura tous un décompte de référence de 1 (le NSArray de A contient une référence à chaque). Tous ces objets restent donc vivants même si rien ne peut jamais les utiliser.

La solution courante consiste à décider que l'une de ces références doit être faible (ne pas contribuer au décompte des références). Cela fonctionnera pour certains modèles d'utilisation, par exemple si vous référencez B1 / B2 / B3 uniquement via A. Cependant, dans d'autres modèles, cela échoue. Par exemple, si vous vous accrocherez parfois à B1 et que vous vous attendez à remonter via le pointeur parent et à trouver A. Avec une référence faible si vous ne maintenez que B1, A peut (et normalement va) s'évaporer et prendre B2 et B3 avec ça.

Parfois, ce n'est pas un problème, mais certaines façons très utiles et naturelles de travailler avec des structures de données complexes sont très difficiles à utiliser avec ARC / MRC.

L'ARC cible donc le même type de problèmes que le GC cible. Cependant, ARC fonctionne sur un ensemble de modèles d'utilisation plus limité que GC, donc si vous preniez un langage GC (comme Java) et y greffiez quelque chose comme ARC, certains programmes ne fonctionneraient plus (ou du moins généreraient des tonnes de mémoire abandonnée). et peut entraîner de graves problèmes de permutation ou manquer de mémoire ou d'espace d'échange).

Vous pouvez également dire que l'ARC accorde une plus grande priorité aux performances (ou peut-être à la prévisibilité) tandis que GC accorde une plus grande priorité à une solution générique. Par conséquent, GC a des demandes CPU / mémoire moins prévisibles et des performances (normalement) inférieures à ARC, mais peut gérer n'importe quel modèle d'utilisation. ARC fonctionnera beaucoup mieux pour de nombreux modèles d'utilisation courants, mais pour quelques modèles d'utilisation (valides!), Il tombera et mourra.

Rayures
la source
"D'un autre côté, certains types de structure de données ne sont pas possibles avec ARC" Je pense que vous vouliez dire que le nettoyage automatique n'est pas possible sans conseils; évidemment, les structures de données le sont.
Steven Fisher
Bien sûr, mais SEUL le nettoyage automatique des objets ObjC est disponible sous ARC donc "pas de nettoyage automatique" == "pas de nettoyage". Je reformulerai puis répondrai quand j'aurai plus de temps.
Stripes
@Stripes: l'équivalent du nettoyage manuel dans ARC est la rupture manuelle des cycles, par exemple foo = nil.
Douglas
"[ARC] aura tendance à avoir des performances plus élevées ... ARC accorde une plus grande priorité aux performances". Je suis surpris de lire que lorsqu'il est bien connu que le comptage des références est beaucoup plus lent que le traçage du ramasse-miettes. flyingfrogblog.blogspot.co.uk/2011/01/…
Jon Harrop
2
En théorie, le GC est plus rapide (chaque manipulation de comptage de référence doit être cohérente avec le cache multiprocesseur, et il y en a beaucoup). En pratique, le seul système GC disponible pour ObjC est beaucoup plus lent. Il est également extrêmement courant pour les systèmes GC de suspendre les threads à des moments aléatoires pendant des périodes de temps perceptibles par l'utilisateur (il existe des systèmes GC en temps réel, mais ils ne sont pas courants, et je pense qu'ils ont des contraintes "intéressantes")
Stripes
4

la magie

Mais plus spécifiquement, ARC fonctionne en faisant exactement ce que vous feriez avec votre code (avec certaines différences mineures). ARC est une technologie de compilation, contrairement à GC qui est l'exécution et aura un impact négatif sur vos performances. ARC suivra les références aux objets pour vous et synthétisera les méthodes de conservation / libération / libération automatique selon les règles normales. À cause de cela, ARC peut également publier des éléments dès qu'ils ne sont plus nécessaires, plutôt que de les jeter dans un pool de libération automatique uniquement pour des raisons de convention.

Certaines autres améliorations incluent la mise à zéro des références faibles, la copie automatique des blocs dans le tas, des accélérations à tous les niveaux (6x pour les pools de libération automatique!).

Une discussion plus détaillée sur la façon dont tout cela fonctionne se trouve dans les documents LLVM sur ARC.

Joshua Weinberg
la source
2
-1 "ARC est une technologie de compilation, contrairement au GC qui est à l'exécution et aura un impact négatif sur vos performances". Les comptages de références sont augmentés au moment de l'exécution, ce qui est très inefficace. C'est pourquoi le suivi des GC comme JVM et .NET est tellement plus rapide.
Jon Harrop
1
@ Jon: En avez-vous une preuve? D'après ma propre lecture, il semble que les nouveaux algorithmes RC fonctionnent généralement aussi bien ou mieux que M&S GC.
xryl669
1
@ xryl669: Il y a une explication complète dans le manuel du GC ( gchandbook.org ). Notez que le traçage! = M&S.
Jon Harrop
3

Cela varie considérablement de la collecte des ordures. Avez-vous vu les avertissements qui vous indiquent que des fuites d'objets peuvent se produire sur différentes lignes? Ces instructions vous indiquent même sur quelle ligne vous avez affecté l'objet. Cela a été pris un peu plus loin et peut désormais insérer retain/ releaseinstructions aux emplacements appropriés, mieux que la plupart des programmeurs, presque 100% du temps. Parfois, il y a des exemples étranges d'objets retenus avec lesquels vous devez l'aider.

FreeAsInBeer
la source
0

Très bien expliqué par la documentation du développeur Apple. Lire "Comment ARC fonctionne"

Pour s'assurer que les instances ne disparaissent pas tant qu'elles sont encore nécessaires, ARC suit le nombre de propriétés, de constantes et de variables faisant actuellement référence à chaque instance de classe. ARC ne désallouera pas une instance tant qu'au moins une référence active à cette instance existe toujours.

Pour s'assurer que les instances ne disparaissent pas tant qu'elles sont encore nécessaires, ARC suit le nombre de propriétés, de constantes et de variables faisant actuellement référence à chaque instance de classe. ARC ne désallouera pas une instance tant qu'au moins une référence active à cette instance existe toujours.

Connaître Diff. entre Garbage collection et ARC: Lisez ceci

Lalit Kumar
la source
0

ARC est une fonction de compilation qui fournit une gestion automatique de la mémoire des objets.

Au lieu de devoir vous rappeler quand utiliser retain, release, et autoreleaseARC évalue les exigences de durée de vie de vos objets et insère automatiquement les appels de gestion de mémoire appropriés pour vous au moment de la compilation. Le compilateur génère également pour vous des méthodes de désallocation appropriées.

Le compilateur insère les retain/releaseappels nécessaires au moment de la compilation, mais ces appels sont exécutés au moment de l'exécution, comme tout autre code.

Le diagramme suivant vous permettra de mieux comprendre le fonctionnement de l'ARC.

entrez la description de l'image ici

Ceux qui sont nouveaux dans le développement iOS et n'ont pas d'expérience de travail sur l'objectif C. Veuillez consulter la documentation d'Apple pour le Guide de programmation de la gestion avancée de la mémoire pour une meilleure compréhension de la gestion de la mémoire.

Yogesh Bharate
la source