2010-09-27 3 views
5

In der Entwicklerdokumentation, heißt es:Der beste Weg, um den Autorelease-Pool auf einem lang laufenden Hintergrund Thread regelmäßig zu entleeren?

Wenn Ihre Anwendung oder Thread erzeugt, viele Autoreleased Objekte langlebig und potenziell ist, sollten Sie in regelmäßigen Abständen ablaufen und Autorelease-Pools erstellen (wie das Application Kit auf der Haupt tut Faden); Andernfalls sammeln sich automatisch freigegebene Objekte an und Ihr Speicherbedarf wächst. Wenn Ihr unabhängiger Thread jedoch keine Cocoa-Aufrufe ausführt, müssen Sie keinen Autorelease-Pool erstellen.

Ich fragte mich, was der beste Weg, dies zu tun ist. Ich habe mehrere Methoden, von denen ich denke, dass sie funktionieren würden, aber ich weiß nicht, welche die "Besten" sind. Im Moment habe ich eine Methode, die den Thread starten und hält sie warten auf Operationen durchführen zu:

- (void)startThread 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    accessoryRunLoop = [NSRunLoop currentRunLoop]; 

    //Add a dummy port to avoid exiting the thread due to no ports being found 
    [accessoryRunLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; 

    while(accessoryThreadIsRunning) 
    { 
     //Keep the thread running until accessoryTheadIsRunning == NO 
     [accessoryRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
    } 

    [pool release]; 
} 

Meine Optionen, die ich denken kann, ist:

1) einen Zähler in der while (accessoryThreadIsRunning) hinzufügen, so dass Alle 50 oder 100 Mal wird der Autorelease Pool geleert und ein neuer erstellt.

2) Jedes Mal, wenn ich eine Methode in diesem Thread ausführe (mit performSelector: onThread :), kann ich einen Autorelease-Pool erstellen und ihn dann am Ende der Methode freigeben.

3) Erstellen Sie einen Timer, so dass ein Pool entleert und dann periodisch erstellt wird.

Ich denke, dass Option 1 ist die beste, aber würde gerne wissen, ob es eine andere Art und Weise, die ich tun sollte. Vielen Dank!

+0

ich denke, es gab in wwdc 10 darüber reden – RolandasR

Antwort

4

Ich würde mit tod einfach beginnen und einfach den Pool bei jedem Durchlauf durch die Schleife erstellen/ablassen.

Wenn es während der Leistungsanalyse als Flaschenhals angezeigt wird, beheben Sie es.

Halten Sie es einfach, bis die Analyse zeigt, dass Komplexität erforderlich ist.

Ich lese gerade Ihre Frage und realisierte etwas völlig boneheaded in meiner Antwort. Wenn Sie eine Run-Schleife ausführen, sollte automatisch für Sie einen Autorelease-Pool verwalten; Es sollte einen Pool am Anfang der Schleife erstellen und am Ende jedes Durchlaufs durch die Schleife ablassen.

Sie müssen nur einen selbst fahren, wenn Sie außerhalb der Runloop noch andere Dinge haben. Ist das der Fall?

Auf jeden Fall ja, das Muster ist:

while(...) { 
    ... create pool ... 
    ... do stuff ... 
    ... drain pool ... 
} 
+0

+1. Autorelease ist schnell. http://www.mikeash.com/pyblog/autorelease-is-fast.html – kubi

+0

+1 vergessen Sie nicht, dass der Haupt-Runloop einer Anwendung den Pool nach jedem Ereignis ableitet. Wenn Apple es nicht für ein Leistungsproblem hält, ist es das wahrscheinlich nicht. – JeremyP

+0

Nur um klar zu sein, sollte ich allok sein, einen neuen Autorelease-Pool vor dem [AccessoryRunLoop runMode:] zuzuordnen, und es danach freigeben? Dies ist auf dem iPhone, also eine Nicht-GC-Umgebung. – Ned

0

Die Laufschleife des Hauptthread bei jedem Durchgang seinen Pool entwässert, so macht es Sinn auch auf andere Themen zu tun. Wenn Sie sich dafür entscheiden, den Pool nur gelegentlich zu leeren, riskieren Sie, dass viele Objekte mit Autorelease für eine lange Zeit freigegeben werden. In der Tat hängt es davon ab, wie viel Speicher Sie bei jedem Durchlauf der Laufschleife freigeben können und wie oft Sie die Laufschleife auslösen. Ich bevorzuge es immer, es bei jedem Durchlauf zu leeren, nur weil es einfach ist und mir hilft, den Speicherbedarf so gering wie möglich zu halten.

0

Der herkömmliche Weg ist, ja, einen Zähler und Abfluss alle 50 oder so zu halten, aber wie bbum sagte, beginnen Sie einfach mit dem Ablassen des Pools jede Schleife, und gehen Sie von dort. ODER Sie könnten -init die Objekte, die Sie benötigen, und keine automatisch freigegebenen Objekte erstellen.(Halten Sie sich einfach von den Fabrikmethoden fern) Denken Sie daran, alle Ihre Objekte an -release.

2

Lassen Sie es jedes Mal ab. Wie andere schon gesagt haben, ist das Löschen eines Autorelease-Pools billig.

Darüber hinaus nicht entwässern kann sehr teuer werden. Wenn Sie genügend Material in Ihrem Autorelease-Pool haben, um Paging zu verursachen, verursachen Sie Festplatten-I/O, und Festplatten-I/O ist buchstäblich Tausende, wenn nicht Millionen von Mal teurer als das Ausführen einer Linked-List-Aufruf-Release auf Zeug. (Und auf Systemen wie iOS, die kein Paging haben, können viele zusätzliche Objekte auf die automatische Freigabe warten, was zu Warnungen bei niedrigem Speicherausmaß führt, die dazu führen können, dass Anwendungen beendet werden oder die Vordergrundanwendung eine Reihe von Nib-Ansichten freigibt , dann muss es später neu erstellt werden ... oder es kann nur dazu führen, dass Ihre Anwendung beendet wird).

Auch wenn Sie nicht genügend zusätzlichen Speicher verwenden, um Warnungen oder Paging bei niedrigem Speicher zu verursachen, werden Sie eine größere Liste von zu entleerenden Elementen erstellen. Mehr Speicherzugriffe werden zwischen Ihrem neuesten Autorelease-Objekt und dem ältesten Objekt bestehen. Es ist sehr viel wahrscheinlicher, dass das älteste Autorelease-Objekt jetzt weiter entfernt in der Speicherhierarchie ist, sodass Ihre Version möglicherweise Cache-Fehler hat, im Gegensatz zu einem L1- oder L2-Cache-Treffer. Also vielleicht 100 mal teurer. Außerdem könnte der Speicher, den Sie freigegeben hätten (und möglicherweise im Cache heiß gewesen wäre), möglicherweise von einem anderen Objekt wiederverwendet worden sein.

So die Autorelease alle 50 bis 100 Mal machen möglicherweise nicht einmal vorzeitige Optimierung zu sein.

Machen Sie eine Freigabe pro Schleife, und wenn das als Engpass auftritt, machen Sie es alle X Male, und stellen Sie sicher, dass es schneller nicht langsamer macht.