Warum gibt ARC bei Verwendung von [NSDate date] keinen Speicher frei, funktioniert aber mit [[NSDate alloction] init]?

8

Ich habe eine Objective-C -Anwendung geschrieben, die gut funktioniert, abgesehen von einem ständig wachsenden Speicherbedarf. Ich verwende ARC unter der letzten Version von Xcode 4.6.2. Mein System ist 10.7.5.

Ich bin sehr neu bei Objective-C und brauche Hilfe, um herauszufinden, was mit meinem Gedächtnis passiert. Ich habe das Problem eingegrenzt, um zu erklären, warum das folgende grundlegende Stück Code sich so verhält wie es.

Dieser Code wird in der Vanilla Cocoa-basierten Anwendungsvorlage hinzugefügt, die Xcode angibt (ARC aktiviert).

Fall A

%Vor%

Alles läuft wie erwartet, ARC holt die Erinnerung im laufenden Betrieb zurück. Die Speicherauslastungshistorie ist nämlich sehr flach. Wenn die for-Schleife endet, benötigt die App etwa 25 MB Speicher.

Fall B

%Vor%

Hier sind die Dinge für mich wirklich mysteriös. Wenn Sie die App nur ausführen, steigt die (tatsächliche) Speichernutzung auf etwa 53 MB und bleibt dann für immer dort.

Beim Ausführen des Zuweisungs-Profiler-Tools kann ich jedoch erkennen, dass am Ende der for-Schleife alle Objekte freigegeben werden, ganz wie Sie es von einem Autorelease-Pool erwarten. Wenn Sie den Körper der for-Schleife mit einem @autoreleasepool {} einschließen, verhält sich Fall B wie erwartet (Fall A).

Also, drei Fragen:

  1. Unter ARC, was ist der Unterschied zwischen der Verwendung der "autoreleased" [NSDate date] und der Alloc-Init-Objekt? (Ich dachte, dass es von anderen Fragen hier keine geben würde.)
  2. Warum scheint ARC beim Ausführen des Codes nicht zu funktionieren?
  3. Warum gibt es einen Unterschied im Speicherverhalten der profilierten Anwendung und der tatsächlichen Anwendung?
akant 20.06.2013, 08:26
quelle

2 Antworten

4

Autorelease-Objekte werden schließlich freigegeben, während sie im Fall alloc / init freigegeben werden, sobald sie nicht mehr verwendet werden.

Dieses Verhalten bewirkt, dass Ihre Objekte für die gesamte Schleife im Speicher verbleiben, falls sie für das später freigegebene Objekt automatisch freigegeben werden. Wenn Sie alloc / init sie verwenden, wird eine release -Methode gesendet innerhalb des Schleifenkörpers.

Sie können die body-Schleife sehr effizient machen, indem Sie sie in ein @autoreleasepool wie folgt einfügen:

%Vor%

Dies gibt ARC einen Hinweis darauf, dass Sie bei jeder Schleifeniteration einen Autorelease-Pool erstellen und freigeben möchten.

Im konkreten Fall wäre die einfachste Option wahrscheinlich, alloc / init Methoden zu verwenden, damit der Compiler das Richtige automatisch erledigt, aber wenn Sie einen Schleifenkörper mit vielen Factory-Methoden haben, die automatisch wieder freigeben Instanzen, der @autoreleasepool Block ist wahrscheinlich ein guter Weg zu gehen.

Als letzte Bemerkung ist @autoreleasepool kein Exklusiv-ARC. Es existierte seit LLVM 3.0, und mit genügend modernen Zielen (nämlich iOS5 und OSX 10.7) ist es bekanntermaßen viel schneller als das altmodische NSAutoreleasePool .

    
Gabriele Petronella 20.06.2013 08:53
quelle
2

[NSDate date] erstellt ein automatisch freigegebenes Objekt, das beim nächsten Eintritt Ihres Programms in die Ereignisschleife freigegeben wird.

Der andere Fall wird innerhalb der Schleife von ARC freigegeben.

Wenn Sie wirklich so etwas tun möchten, können Sie Ihren eigenen Pool für die automatische Freigabe erstellen und ihn regelmäßig leeren. Siehe zum Beispiel Objective-C: Warum ist Autorelease (@ Autorespulepool) noch mit ARC benötigt?

    
Bryan 20.06.2013 08:36
quelle