Welche Art von Lecks verhindert oder minimiert die automatische Referenzzählung in Objective-C nicht?

235

Auf den Mac- und iOS-Plattformen werden Speicherverluste häufig durch unveröffentlichte Zeiger verursacht. Traditionell war es immer von größter Bedeutung, Ihre Zuordnungen, Kopien und Aufbewahrungen zu überprüfen, um sicherzustellen, dass jede eine entsprechende Freigabemeldung enthält.

Die mit Xcode 4.2 gelieferte Toolchain führt die automatische Referenzzählung (ARC) mit der neuesten Version des LLVM-Compilers ein , die dieses Problem vollständig beseitigt, indem der Compiler Ihre Speicher für Sie speicherverwaltet. Das ist ziemlich cool und verkürzt die unnötige, alltägliche Entwicklungszeit und verhindert viele unachtsame Speicherlecks, die mit einem angemessenen Gleichgewicht zwischen Beibehalten und Freigeben leicht zu beheben sind. Selbst Autorelease-Pools müssen anders verwaltet werden, wenn Sie ARC für Ihre Mac- und iOS-Apps aktivieren (da Sie keine eigenen NSAutoreleasePoolmehr zuweisen sollten ).

Aber welche anderen Speicherlecks verhindern nicht , dass ich noch aufpassen muss?

Was sind die Unterschiede zwischen ARC unter Mac OS X und iOS und der Speicherbereinigung unter Mac OS X?

BoltClock
quelle

Antworten:

262

Das primäre Speicherproblem, dessen Sie sich noch bewusst sein müssen, ist das Beibehalten von Zyklen. Dies tritt auf, wenn ein Objekt einen starken Zeiger auf ein anderes hat, das Zielobjekt jedoch einen starken Zeiger auf das Original hat. Selbst wenn alle anderen Verweise auf diese Objekte entfernt werden, bleiben sie aneinander hängen und werden nicht freigegeben. Dies kann auch indirekt durch eine Kette von Objekten geschehen, bei denen das letzte in der Kette möglicherweise auf ein früheres Objekt verweist.

Es ist aus diesem Grund , dass die __unsafe_unretainedund __weakEigentum - Qualifikation bestehen. Ersteres behält kein Objekt bei, auf das es zeigt, lässt jedoch die Möglichkeit offen, dass dieses Objekt verschwindet und auf ein schlechtes Gedächtnis verweist, während letzteres das Objekt nicht beibehält und sich automatisch auf Null setzt, wenn sein Ziel freigegeben wird. Von den beiden __weakwird im Allgemeinen auf Plattformen bevorzugt, die dies unterstützen.

Sie würden diese Qualifikationsmerkmale beispielsweise für Delegaten verwenden, bei denen das Objekt seinen Delegaten nicht behalten und möglicherweise zu einem Zyklus führen soll.

Ein weiteres wichtiges Problem im Zusammenhang mit dem Speicher ist die Behandlung von Core Foundation-Objekten und des zugewiesenen Speichers malloc()für Typen wie char*. ARC verwaltet diese Typen nicht, sondern nur Objective-C-Objekte. Sie müssen sich also weiterhin selbst mit ihnen befassen. Core Foundation-Typen können besonders schwierig sein, da sie manchmal mit passenden Objective-C-Objekten überbrückt werden müssen und umgekehrt. Dies bedeutet, dass die Steuerung von ARC hin und her übertragen werden muss, wenn zwischen CF-Typen und Objective-C eine Brücke geschlagen wird. Einige Schlüsselwörter im Zusammenhang mit dieser Überbrückung wurden hinzugefügt, und Mike Ash hat in seiner langwierigen ARC- Beschreibung eine hervorragende Beschreibung verschiedener Überbrückungsfälle .

Darüber hinaus gibt es einige andere weniger häufige, aber immer noch potenziell problematische Fälle, auf die in der veröffentlichten Spezifikation ausführlich eingegangen wird.

Ein Großteil des neuen Verhaltens, das darauf basiert, Objekte so lange zu behalten, wie es einen starken Zeiger auf sie gibt, ist der Speicherbereinigung auf dem Mac sehr ähnlich. Die technischen Grundlagen sind jedoch sehr unterschiedlich. Anstatt einen Garbage Collector-Prozess zu haben, der in regelmäßigen Abständen ausgeführt wird, um Objekte zu bereinigen, auf die nicht mehr verwiesen wird, basiert diese Art der Speicherverwaltung auf den strengen Aufbewahrungs- / Freigaberegeln, die wir alle in Objective-C einhalten müssen.

ARC übernimmt einfach die sich wiederholenden Speicherverwaltungsaufgaben, die wir seit Jahren ausführen müssen, und verlagert sie an den Compiler, damit wir uns nie wieder um sie kümmern müssen. Auf diese Weise haben Sie keine Probleme mit dem Anhalten oder Sägezahnspeicherprofilen, die auf mit Müll gesammelten Plattformen auftreten. Ich habe beide in meinen Mac-Anwendungen mit Müllsammlung erlebt und bin gespannt, wie sie sich unter ARC verhalten.

Weitere Informationen zur Garbage Collection im Vergleich zu ARC finden Sie in dieser sehr interessanten Antwort von Chris Lattner auf der Objective-C-Mailingliste , in der er viele Vorteile von ARC gegenüber der Objective-C 2.0-Garbage Collection auflistet. Ich bin auf einige der von ihm beschriebenen GC-Probleme gestoßen.

Brad Larson
quelle
2
Danke für die ausführliche Antwort. Ich hatte das gleiche Problem, bei dem ich einen Delegaten unter _unsafe_unretained definiert habe und meine Anwendung abgestürzt bin. Später wurde sie durch Ändern auf strong behoben, aber jetzt ist ein Speicherverlust aufgetreten. Also habe ich es in schwach geändert und funktioniert wie ein Zauber.
Chathuram
@ichathura Wow! Du hast mich aus dem ARC-Sumpf gerettet. Ich habe den gleichen Absturz bei der Verwendung von CMPopTipView festgestellt.
Nianliang
@BradLarson: "Sie haben keine Halteprobleme oder Sägezahnspeicherprofile, die auf Müllsammelplattformen auftreten." Ich würde schlechtere Stopp- und Sägezahnspeicherprofile von der bereichsbasierten Reklamation und eine viel schlechtere Leistung von der Referenzzählung erwarten, daher würde ich mir einen echten Vergleich wünschen.
Jon Harrop
Brad, der Link von Chris Lattner ist tot . Ich bin nicht 100%, aber ich habe diesen anderen Link gefunden. Was ich denke, ist das, worauf Sie verlinken wollten: lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160208/…
Honey
1
@Honey - Danke, dass du darauf hingewiesen hast. Der Link, den Sie verlinken, ist etwas anders, aber ich habe den toten Link durch eine archivierte Version der ursprünglichen Nachricht ersetzt. Es befindet sich in Mailinglisten-Archiven, die irgendwo verfügbar sein sollten, aber ich werde nachsehen, ob ich ihren neuen Speicherort finden kann.
Brad Larson
14

ARC hilft Ihnen nicht mit Nicht-ObjC-Speicher, zum Beispiel, wenn Sie malloc()etwas haben, brauchen Sie es immer noch free().

ARC kann getäuscht werden, performSelector:wenn der Compiler nicht herausfinden kann, was der Selektor ist (der Compiler generiert eine Warnung dazu).

ARC generiert auch Code gemäß den ObjC-Namenskonventionen. Wenn Sie also ARC- und MRC-Code mischen, können Sie überraschende Ergebnisse erzielen, wenn der MRC-Code nicht das tut, was der Compiler für die Namen vielversprechend hält.

Streifen
quelle
7

In meiner Anwendung sind aufgrund der folgenden 4 Probleme Speicherverluste aufgetreten:

  1. NSTimer werden nicht ungültig, wenn View Controller geschlossen werden
  2. Vergessen, Beobachter aus dem NSNotificationCenter zu entfernen, wenn der View Controller geschlossen wird.
  3. Starke Verweise auf sich selbst in Blöcken halten.
  4. Verwenden starker Verweise auf Delegaten in View Controller-Eigenschaften

Zum Glück bin ich auf folgenden Blog-Beitrag gestoßen und konnte ihn korrigieren: http://www.reigndesign.com/blog/debugging-retain-cycles-in-objective-c-four-likely-culprits/

Ed-E G.
quelle
0

ARC verwaltet auch keine CoreFoundation-Typen. Sie können sie "überbrücken" (mit CFBridgingRelease()), aber nur, wenn Sie sie als Objective-C / Cocoa-Objekt verwenden möchten. Beachten Sie, dass CFBridgingRelease die Anzahl der CoreFoundation-Retains nur um 1 verringert und in den ARC von Objective-C verschiebt.

MaddTheSane
quelle
0

Xcode 9 bietet ein großartiges Tool, um solche Probleme zu finden. Es heißt: " Debug Memory Graph ". Wenn Sie es verwenden, können Sie Ihr durchgesickertes Objekt nach Klassentyp finden und klar sehen, wer einen starken Bezug dazu hat, indem Sie es von dort freigeben, um Ihr Problem zu lösen. Es erkennt auch Speicherzyklen.

Weitere Informationen zur Verwendung finden Sie hier

WILL K.
quelle