Kann mir jemand kurz erklären, wie ARC funktioniert? Ich weiß, dass es sich von Garbage Collection unterscheidet, aber ich habe mich nur gefragt, wie es genau funktioniert.
Wenn ARC das tut, was GC tut, ohne die Leistung zu beeinträchtigen, warum verwendet Java dann GC? Warum wird ARC nicht auch verwendet?
Antworten:
Jeder neue Entwickler, der zu Objective-C kommt, muss die strengen Regeln für das Aufbewahren, Freigeben und automatische Freigeben von Objekten kennen. Diese Regeln legen sogar Namenskonventionen fest, die die Anzahl der von Methoden zurückgegebenen Objekte beibehalten. Die Speicherverwaltung in Objective-C wird zur zweiten Natur, wenn Sie sich diese Regeln zu Herzen nehmen und sie konsequent anwenden, aber selbst die erfahrensten Cocoa-Entwickler rutschen von Zeit zu Zeit aus.
Mit dem Clang Static Analyzer erkannten die LLVM-Entwickler, dass diese Regeln zuverlässig genug waren, um ein Tool zu erstellen, das auf Speicherverluste und Überfreigaben in den Pfaden Ihres Codes hinweist.
Die automatische Referenzzählung (ARC) ist der nächste logische Schritt. Wenn der Compiler erkennen kann, wo Sie Objekte aufbewahren und freigeben sollen, lassen Sie ihn diesen Code einfügen. Starre, sich wiederholende Aufgaben sind das, was Compiler und ihre Brüder großartig können. Menschen vergessen Dinge und machen Fehler, aber Computer sind viel konsistenter.
Dies befreit Sie jedoch nicht vollständig von der Sorge um die Speicherverwaltung auf diesen Plattformen. In meiner Antwort hier beschreibe ich das Hauptproblem, auf das Sie achten müssen (Zyklen beibehalten). Dies erfordert möglicherweise ein wenig Nachdenken von Ihrer Seite, um schwache Zeiger zu markieren. Dies ist jedoch im Vergleich zu dem, was Sie in ARC gewinnen, geringfügig.
Im Vergleich zur manuellen Speicherverwaltung und Speicherbereinigung bietet ARC das Beste aus beiden Welten, da keine Schreib- / Freigabecodes mehr geschrieben werden müssen, ohne dass die in einer Speicherbereinigungsumgebung angezeigten Speicherprofile zum Anhalten und Sägezahn vorhanden sind. Die einzigen Vorteile, die die Speicherbereinigung gegenüber dieser Funktion hat, sind ihre Fähigkeit, mit Aufbewahrungszyklen umzugehen, und die Tatsache, dass Zuweisungen atomarer Eigenschaften kostengünstig sind (wie hier erläutert ). Ich weiß, dass ich meinen gesamten vorhandenen Mac GC-Code durch ARC-Implementierungen ersetze.
Ob dies auf andere Sprachen ausgedehnt werden könnte, scheint auf das Referenzzählsystem in Objective-C ausgerichtet zu sein. Es mag schwierig sein, dies auf Java oder andere Sprachen anzuwenden, aber ich weiß nicht genug über die Details des Low-Level-Compilers, um dort eine endgültige Aussage zu treffen. Angesichts der Tatsache, dass Apple diese Bemühungen in LLVM vorantreibt, wird Objective-C an erster Stelle stehen, sofern nicht eine andere Partei selbst erhebliche Ressourcen dafür bereitstellt.
Die Enthüllung dieser schockierten Entwickler auf der WWDC, sodass die Leute nicht wussten, dass so etwas getan werden könnte. Es kann im Laufe der Zeit auf anderen Plattformen erscheinen, ist jedoch derzeit nur für LLVM und Objective-C verfügbar.
quelle
ARC spielt nur das alte Retain / Release (MRC) ab, wobei der Compiler herausfindet, wann Retain / Release aufgerufen werden soll. Es weist tendenziell eine höhere Leistung, eine geringere Spitzenauslastung des Speichers und eine besser vorhersehbare Leistung als ein GC-System auf.
Andererseits sind einige Arten von Datenstrukturen mit ARC (oder MRC) nicht möglich, während GC sie verarbeiten kann.
Wenn Sie beispielsweise eine Klasse mit dem Namen node haben und node ein NSArray mit untergeordneten Elementen und einen einzelnen Verweis auf das übergeordnete Element hat, der mit GC "nur funktioniert". Mit ARC (und auch der manuellen Referenzzählung) haben Sie ein Problem. Jeder gegebene Knoten wird von seinen untergeordneten und auch von seinen übergeordneten Knoten referenziert.
Mögen:
Alles ist in Ordnung, während Sie A verwenden (z. B. über eine lokale Variable).
Wenn Sie damit fertig sind (und B1 / B2 / B3), wird ein GC-System schließlich entscheiden, alles zu betrachten, was es finden kann, beginnend mit den Stapel- und CPU-Registern. Es wird niemals A, B1, B2, B3 finden, also werden sie finalisiert und der Speicher in andere Objekte zurückgeführt.
Wenn Sie ARC oder MRC verwenden und mit A abschließen, hat es eine Nachzählung von 3 (B1, B2 und B3 beziehen sich alle darauf), und B1 / B2 / B3 haben alle eine Referenzanzahl von 1 (A's NSArray enthält eine Referenz auf jeder). Alle diese Objekte bleiben also lebendig, obwohl nichts sie jemals verwenden kann.
Die übliche Lösung besteht darin, zu entscheiden, dass eine dieser Referenzen schwach sein muss (nicht zur Referenzanzahl beitragen). Dies funktioniert für einige Verwendungsmuster, z. B. wenn Sie B1 / B2 / B3 nur über A referenzieren. In anderen Mustern schlägt dies jedoch fehl. Zum Beispiel, wenn Sie manchmal an B1 festhalten und erwarten, über den übergeordneten Zeiger wieder nach oben zu klettern und A zu finden. Mit einer schwachen Referenz, wenn Sie nur an B1 festhalten, kann (und wird) A verdampfen und B2 und B3 nehmen damit.
Manchmal ist dies kein Problem, aber einige sehr nützliche und natürliche Methoden zum Arbeiten mit komplexen Datenstrukturen sind mit ARC / MRC sehr schwierig zu verwenden.
ARC zielt also auf die gleichen Probleme ab, auf die GC abzielt. ARC arbeitet jedoch mit einer begrenzten Anzahl von Verwendungsmustern als GC. Wenn Sie also eine GC-Sprache (wie Java) verwenden und etwas wie ARC darauf pfropfen, funktionieren einige Programme nicht mehr (oder generieren zumindest Tonnen von verlassenem Speicher und kann schwerwiegende Auslagerungsprobleme verursachen oder nicht genügend Speicher oder Auslagerungsspeicher haben).
Sie können auch sagen, dass ARC der Leistung (oder vielleicht der Vorhersagbarkeit) eine höhere Priorität einräumt, während GC der generischen Lösung eine höhere Priorität einräumt. Infolgedessen hat GC weniger vorhersehbare CPU- / Speicheranforderungen und (normalerweise) eine geringere Leistung als ARC, kann jedoch jedes Nutzungsmuster verarbeiten. ARC funktioniert viel besser für viele, viele gängige Nutzungsmuster, aber für einige (gültige!) Nutzungsmuster fällt es um und stirbt ab.
quelle
foo = nil
.Magie
Genauer gesagt funktioniert ARC genau so, wie Sie es mit Ihrem Code tun würden (mit bestimmten geringfügigen Unterschieden). ARC ist eine Technologie zur Kompilierungszeit, im Gegensatz zu GC, die zur Laufzeit verwendet wird und sich negativ auf Ihre Leistung auswirkt. ARC verfolgt die Verweise auf Objekte für Sie und synthetisiert die Retain / Release / Autorelease-Methoden gemäß den normalen Regeln. Aus diesem Grund kann ARC auch Dinge freigeben, sobald sie nicht mehr benötigt werden, anstatt sie nur aus Gründen der Konvention in einen Autorelease-Pool zu werfen.
Einige andere Verbesserungen umfassen das Nullsetzen schwacher Referenzen, das automatische Kopieren von Blöcken auf den Heap und allgemeine Beschleunigungen (6x für Autorelease-Pools!).
Eine ausführlichere Beschreibung der Funktionsweise finden Sie in den LLVM-Dokumenten zu ARC.
quelle
Es unterscheidet sich stark von der Speicherbereinigung. Haben Sie die Warnungen gesehen, die darauf hinweisen, dass möglicherweise Objekte in verschiedenen Leitungen auslaufen? Diese Anweisungen sagen Ihnen sogar, in welcher Zeile Sie das Objekt zugewiesen haben. Dies ist noch einen Schritt weiter gegangen und kann nun
retain
/release
Anweisungen fast 100% der Zeit an den richtigen Stellen einfügen , besser als die meisten Programmierer. Gelegentlich gibt es einige seltsame Fälle von beibehaltenen Objekten, bei denen Sie Hilfe benötigen.quelle
Sehr gut erklärt durch Apple Entwickler Dokumentation. Lesen Sie "Wie ARC funktioniert"
Diff zu kennen. zwischen Garbage Collection und ARC: Lesen Sie dies
quelle
ARC ist eine Compilerfunktion, die die automatische Speicherverwaltung von Objekten ermöglicht.
Anstatt sich merken zu müssen, wann und verwendet werden
retain, release
sollautorelease
, wertet ARC die Lebensdaueranforderungen Ihrer Objekte aus und fügt beim Kompilieren automatisch die entsprechenden Speicherverwaltungsaufrufe für Sie ein. Der Compiler generiert auch geeignete Dealloc-Methoden für Sie.Der Compiler fügt die erforderlichen
retain/release
Aufrufe zur Kompilierungszeit ein, diese Aufrufe werden jedoch wie jeder andere Code zur Laufzeit ausgeführt.Das folgende Diagramm gibt Ihnen ein besseres Verständnis der Funktionsweise von ARC.
Diejenigen, die neu in der iOS-Entwicklung sind und keine Berufserfahrung mit Ziel C haben, finden Sie in der Apple-Dokumentation zum Programmierhandbuch für Advanced Memory Management ein besseres Verständnis der Speicherverwaltung.
quelle