Warum fügen die Xcode 4.x-Vorlagen für Objective-C -Kommandozeilen und iOS -Programme den Code @autoreleasepool {}
part wrapping main()
hinzu? Beachten Sie, dass dies für die OS X Anwendungsvorlage nicht möglich ist.
Warum machen OS X-Anwendungen nicht dasselbe? Warum verwenden beide nicht die gleiche Methode?
Schließlich, da alle Speicher freigegeben werden, wenn ein Programm beendet wird, warum ist all dies von praktisch wichtig?
Oder um es anders zu fragen, welche praktischen Konsequenzen ergeben sich aus dem Weglassen von @autoreleasepool { ... }
in main()
für eine Kommandozeile oder ein iOS Objective-C Programm?
Diese beiden Teile des Codes kompilieren und scheinen gleich zu funktionieren:
1.
%Vor%2.
%Vor% Beachten Sie, dass mir die Erklärung im ARC-Kontext nur wichtig ist. ARC verbietet die explizite Verwendung von autorelease
.
autorelease
funktioniert nicht, wenn auf dem Stapel kein Autorelease-Pool vorhanden ist.
Es ist nicht wirklich notwendig, in objective-c (wie in Ihren Beispielen) automatisch freigegebene Objekte zu verwenden, so dass Sie es theoretisch weglassen können. Die meisten Apple-Frameworks verwenden jedoch stark removered Objekte.
Normalerweise sollte jeder Thread mindestens einen Autorelease-Pool haben, andernfalls ist die Verwendung eines Obj-C-Codes sehr unsicher. Das Einrichten eines Autorelease-Pools zu Beginn von main
ist dann eine sehr gute Übung.
BEARBEITEN:
In ARC, obwohl explizit autorelease
verboten ist, sind autorelease
Aufrufe immer noch da (vom Compiler hinzugefügt). Das impliziert die Notwendigkeit eines Autorelease-Pools.
Das hat nichts mit der Freigabe des Speichers zu tun. Die Existenz eines Autorelease-Pools ist notwendig. Selbst wenn es nie leer ist.
Ich nehme an, dass OS X den Autorelease-Pool nicht zur Vorlage hinzufügt, da die Programmierer auch einen Garbage Collector verwenden können (obwohl er jetzt veraltet ist).
EDIT 2:
Ich habe gerade ein OS X-Projekt erstellt und das @autoreleasepool
ist da. In der Tat ist die einzige Vorlage ohne es ein "Core Foundation" -Projekt, das nicht wirklich Obj-C ist, es ist reines C.
EDIT 3: (Nach einigem Nachdenken und etwas Googeln)
Mit der Einführung von ARC wurden Autorelease-Pools neu geschrieben. Als sie zuvor ein Framework-Feature waren, sind sie jetzt ein Feature für Sprache (Obj-C). Sie sind unterschiedlich implementiert. Es scheint, dass jeder neue Thread jetzt einen impliziten Autorelease-Pool hat. Durch die Verwendung von @autoreleasepool
wird nicht wirklich ein neuer Autorelease-Pool auf einem Thread-Stack erstellt, sondern nur eine Markierung im impliziten Autorelease-Pool (so dass alles, was nach der Markierung automatisch freigegeben wurde, gelöscht werden kann). Das bedeutet, dass es keine Möglichkeit gibt, ein Beispiel für Triggering-Warnungen oder -Fehler zu erstellen, wenn @autoreleasepool
weggelassen wird.
Dies wird jedoch als Implementierungsdetail betrachtet, sodass es in Zukunft leicht geändert werden kann (oder wenn ein anderer Compiler verwendet wird!). Aus diesem Grund empfiehlt es sich, für jeden neuen Thread (z. B. in @autoreleasepool
documentation) immer noch -[NSThread detachWithSelector:..]
einzurichten.
In Ihrem Codebeispiel oben verwenden Sie keine Objekte, die jemals wieder freigegeben wurden.
Aber wenn Sie so etwas tun:
%Vor% Das Bit " @autoreleasepool
" wäre eigentlich ein bisschen nützlicher.
Looking In Apples Dokumentation für Autoreleasepool heißt es:
Am Ende des Autorelease-Pool-Blocks, Objekte, die ein empfangen haben Autorelease-Nachricht innerhalb des Blocks werden eine Freigabenachricht gesendet Objekt erhält eine Freigabenachricht für jedes Mal, wenn es gesendet wurde Autorelease-Nachricht innerhalb des Blocks.
Wenn Sie also viele von automatisch freigegebenen Objekten haben (und es gibt viele, die Sie erstellen können, die als NSArray, NSDictionary, NSString usw. enden), helfen diese Autorelease-Pools, den Speicher freizuhalten .
Die Anwendungsvorlage enthält " @autoreleasepool
" in main.m, da auf Geräten wie dem iPhone oder iPad die Speicherauslastung kritisch ist und wir sicherstellen möchten, dass der gesamte Speicher ordnungsgemäß freigegeben wird, wenn die Anwendung den " UIApplicationMain
"(nicht sehr wahrscheinlich, da die meisten Leute ihre iPhone Apps laufen lassen, bis sie neu starten, aber es könnte passieren).
Sie brauchen es, weil die Dokumentation sagt, dass Sie es brauchen. Das sollte reichen, vertraue der Dokumentation:
Normalerweise müssen Sie keine eigenen Autorelease-Pool-Blöcke erstellen, aber es gibt Situationen, in denen Sie dies tun müssen oder es sinnvoll ist.
...
Cocoa erwartet immer, dass Code in einem Autorelease-Pool ausgeführt wird blockieren, sonst werden automatisch freigegebene Objekte nicht freigegeben und Ihr Anwendung leckt Speicher. (Wenn Sie eine Autorelease-Nachricht außerhalb senden von einem Autorelease-Poolblock protokolliert Cocoa eine geeignete Fehlermeldung.)
... Es gibt jedoch drei Fälle, in denen Sie Ihre eigenen Autorelease-Pool-Blöcke verwenden könnten:
- Wenn Sie ein Programm schreiben, das nicht auf einem UI-Framework wie einem Befehlszeilentool basiert.
- ...
- ...
...
Wenn Sie ein Foundation-only-Programm schreiben oder einen Thread trennen, müssen Sie einen eigenen Autorelease-Poolblock erstellen.
Wenn es keinen Autorelease-Pool gibt ... dann funktionieren die meisten Dinge immer noch gut, aber es sind "die meisten" Dinge, nicht "alle" Dinge. Sie geben nur zwei Gründe an, aber es gibt möglicherweise andere Gründe, die nicht dokumentiert sind, und all dieses Verhalten kann jederzeit in der Zukunft geändert werden.
Wenn Sie die empfohlenen Best Practices befolgen, sollte Ihr Code auch in 20 Jahren noch einwandfrei funktionieren, aber wenn Sie dies nicht tun, stürzt er möglicherweise einmal in fünfzig Ausführungen ab dem nächsten xxx-Update des Betriebssystems ab.
Wahrscheinlich würde dieses Zitat aus der Apple-Dokumentation helfen:
Wenn Ihr unabhängiger Thread keine Cocoa-Aufrufe ausführt, müssen Sie keinen Poolpool für die automatische Freigabe verwenden.
Es könnte auf alle Threads extrapoliert werden, auch wenn es einen Master gibt (wo "main" ist).
Tags und Links objective-c clang macos memory-management