Frage

Ich wollte etwas klarstellen.

Nehmen wir an, ich habe den folgenden Code:

- (void) viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];
  for (int i = 0; i < 5000000; i++) {
    NSString *s = [NSString stringWithFormat:@"Hello, %@!", @"World"];
  }
}

Dadurch werden innerhalb dieses Funktionsaufrufs 5 Millionen automatisch freigegebene Zeichenfolgen erstellt.Ich habe damit gerechnet, dass diese Objekte bis zum Beenden der Anwendung erhalten bleiben, da der einzige @autoreleasepool, den ich sehe, derjenige ist, der die Anwendungsinstanziierung in main.m umschließt.Das ist jedoch nicht der Fall.Am Ende dieses Funktionsaufrufs scheint es, als würden alle ihre Freigabe aufrufen und aus dem Speicher entfernt werden.

Dieses Dokument:

https://developer.apple.com/library/mac/documentation/cocoa/reference/foundation/Classes/NSAutoreleasePool_Class/Reference/Reference.html

Darin heißt es: „Das Application Kit erstellt zu Beginn jedes Zyklus der Ereignisschleife einen Autorelease-Pool im Hauptthread und entleert ihn am Ende, wodurch alle automatisch freigegebenen Objekte freigegeben werden, die während der Verarbeitung eines Ereignisses generiert werden.“

Das macht für mich Sinn, aber das ist unter UIKit und nicht unter Application Kit.Meine Frage ist: Macht UIKit/Cocoa Touch in diesem Fall dasselbe, oder gibt es eine andere Erklärung dafür, dass meine Objekte freigegeben werden?

Danke!

War es hilfreich?

Lösung 2

Ja, UIKit macht dasselbe.Der vom System erstellte Haupt-Thread-Autorelease-Pool wird am Ende jedes Ausführungsschleifenzyklus geleert.Es ist wahrscheinlich am besten, sich in Ihrem eigenen Code nicht auf diese genaue Lebensdauer zu verlassen.Wenn Sie manuell einen neuen Thread erstellen (z. B.NSThread) sind Sie für die Erstellung des Autorelease-Pools in diesem Thread verantwortlich.

BEARBEITEN:Robs Antwort liefert einige gute zusätzliche Informationen zum Verhalten unter ARC.Im Allgemeinen kann man mit Fug und Recht sagen, dass die Wahrscheinlichkeit, dass Objekte im Autorelease-Pool landen, aufgrund einiger Optimierungen, die ARC vornehmen kann, geringer ist.

Andere Tipps

Andrew hat Ihre Hauptfrage so beantwortet: Ja, Ihr Autorelease-Pool wird bei jedem Zyklus der Hauptlaufschleife geleert.Also alle Autorelease-Objekte, die in erstellt wurden viewDidLoad kann sofort entleert werden, wenn Sie zur Hauptlaufschleife zurückkehren.Sie werden sicherlich nicht „bis zur Beendigung der Bewerbung“ aufbewahrt.

Aber wir sollten vorsichtig sein:Sie gehen eindeutig davon aus, dass diese Objekte einem Autorelease-Pool hinzugefügt werden.Ein paar Vorbehalte zu dieser Annahme:

  1. In der Vergangenheit (und immer noch für die ARC-MRC-Interoperabilität erforderlich), wenn Objekte von Methoden zurückgegeben wurden, deren Namen nicht mit begannen alloc, new, copy, oder mutableCopy, diese Objekte würden Objekte automatisch freigeben und nur dann freigegeben, wenn der Autorelease-Pool geleert wurde (d. h.als Sie zur Laufschleife zurückkehrten).

  2. Aber ARC ist bei der Minimierung des Bedarfs an Autorelease-Pools schlauer geworden (siehe http://rentzsch.tumblr.com/post/75082194868/arcs-fast-autorelease, das diskutiert callerAcceptsFastAutorelease, jetzt genannt callerAcceptsOptimizedReturn aufgerufen von prepareOptimizedReturn), sodass Sie dies oft nicht sehen werden autorelease Verhalten.Wenn also sowohl die Bibliothek als auch der Aufrufer ARC verwenden, werden Objekte möglicherweise nicht im Autorelease-Pool platziert, sondern ARC gibt sie geschickt sofort frei, wenn sie nicht benötigt werden.

    Bei modernen ARC-Projekten sind Autorelease-Pools im Allgemeinen nicht erforderlich.In bestimmten Sonderfällen kann die Verwendung von Autorelease-Pools jedoch dennoch von Vorteil sein.Einen dieser Fälle werde ich im Folgenden skizzieren.

Betrachten Sie den folgenden Code:

#import "ViewController.h"
#import <sys/kdebug_signpost.h>

typedef enum : NSUInteger {
    InnerLoop = 1,
    MainLoop = 2
} MySignPostCodes;

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"png"];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        kdebug_signpost_start(MainLoop, 0, 0, 0, 1);
        for (int j = 0; j < 500; i++) {
            NSData *data = [NSData dataWithContentsOfURL:fileURL];
            UIImage *image = [[UIImage alloc] initWithData:data];
            NSLog(@"%p", NSStringFromCGSize(image.size));  // so it's not optimized out
            [NSThread sleepForTimeInterval:0.01];
        }
        kdebug_signpost_end(MainLoop, 0, 0, 0, 1);
    });
}

@end

Der folgende Code fügt dem Autorelease-Pool 500.000 Objekte hinzu, die erst geleert werden, wenn ich zur Ausführungsschleife zurückkehre:

no pool

In diesem Fall könnten Sie einen Autorelease-Pool verwenden, um die Obergrenze zu minimieren:

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"png"];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        kdebug_signpost_start(MainLoop, 0, 0, 0, 1);
        for (int j = 0; j < 5; j++) {
            @autoreleasepool {
                kdebug_signpost_start(InnerLoop, 0, 0, 0, 2);
                for (long i = 0; i < 100; i++) {
                    NSData *data = [NSData dataWithContentsOfURL:fileURL];
                    UIImage *image = [[UIImage alloc] initWithData:data];
                    NSLog(@"%p", NSStringFromCGSize(image.size));  // so it's not optimized out
                    [NSThread sleepForTimeInterval:0.01];
                }
                kdebug_signpost_end(InnerLoop, 0, 0, 0, 2);
            }
        }
        kdebug_signpost_end(MainLoop, 0, 0, 0, 1);
    });
}

@end

pool

Unterm Strich ist es bei ARC nicht immer offensichtlich, wann ein Autorelease-Objekt verwendet wurde und wann es es explizit freigibt, wenn die Variable außerhalb des Gültigkeitsbereichs liegt.Sie können dies jederzeit bestätigen, indem Sie das Verhalten in Instruments untersuchen.

Abgesehen davon wäre ich vorsichtig, wenn ich bei der Verwendung von nicht zu viele allgemeine Schlussfolgerungen zur Speicherverwaltung ziehe NSString Klasse, da sie stark optimiert wurde und nicht immer den Standardpraktiken der Speicherverwaltung entspricht.

Ich würde davon ausgehen, dass, wenn Sie ein neues Objekt einer Referenz zuweisen, die früher ein Objekt enthielt Das Originalobjekt wird sofort freigegeben (Wenn nichts anderes darauf hinweist, geht die Ref-Zählung auf Null) unter Verwendung von ARC und unter Annahme der Standardeinstellung strong Referenz wie in Ihrem Schleifenbeispiel.

MyObject *object = [[MyObject alloc] init]; // obj1, ref count 1 because strong
object = [[MyObject alloc] init]; // obj2, ref count of obj1 should be 0
                                  // so obj1 gets released

Apple-Notizen in Übergang zu ARC-Versionshinweisen

Versuchen Sie nicht mehr darüber nachzudenken, wo die Retain-/Release-Aufrufe platziert werden, und denken Sie stattdessen über Ihre Anwendungsalgorithmen nach.Denken Sie über „starke und schwache“ Zeiger in Ihren Objekten, über Objektbesitz und mögliche Aufbewahrungszyklen nach.

Es hört sich so an, als ob release wird ein Objekt aufgerufen, wenn es einen neuen Wert von Clang zugewiesen hat Clang 3.4 Dokumentation Objektiv-C Automatische Referenzzählung (ARC)

Die Zuweisung erfolgt bei der Auswertung eines Zuweisungsoperators.Die Semantik variiert je nach Qualifikation:

Bei __strong-Objekten wird zunächst der neue Pointee beibehalten;Zweitens ist der LValue mit primitiver Semantik beladen;Drittens wird der neue Punkte mit primitiven Semantik in den Lvalue aufbewahrt.Und schließlich wird der alte Pointee veröffentlicht.Dies geschieht nicht atomar;Die externe Synchronisation muss verwendet werden, um dies angesichts von gleichzeitigen Lasten und Geschäften sicher zu machen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top