2010-09-27 8 views
5

Nella documentazione per gli sviluppatori, che dice:Il modo migliore per scaricare periodicamente il pool di autorelease su un thread in background di lunga durata?

Se l'applicazione o il filo è di lunga durata e potenzialmente genera un sacco di oggetti autoreleased, si dovrebbe periodicamente scarico e creare pool autorelease (come l'Application Kit fa sul principale filo); in caso contrario, gli oggetti autoreleased si accumulano e l'ingombro della memoria aumenta. Se, tuttavia, il thread separato non effettua chiamate Cocoa, non è necessario creare un pool autorelease.

Mi chiedevo quale sia il modo migliore per farlo. Ho diversi metodi che penso funzionerebbero, ma non so quale sia il "migliore". Al momento ho un metodo che avvia il filo e la mantiene in attesa per le operazioni da eseguire:

- (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]; 
} 

Opzioni per il mio mi viene in mente sono:

1) aggiungere un contatore nel mentre (accessoryThreadIsRunning) in modo che ogni 50 o 100 volte scaricherà il pool di autorelease e ne creerà uno nuovo.

2) Ogni volta che eseguo un metodo in tale thread (utilizzando performSelector: onThread :), posso creare un pool di autorelease e quindi rilasciarlo alla fine del metodo.

3) Effettuare un timer in modo che una piscina venga scaricata e quindi creata periodicamente.

Penso che l'opzione 1 sia la migliore, ma vorrei sapere se c'è un modo diverso che dovrei fare. Grazie!

+0

Penso che ci fosse un discorso in wwdc 10 su quello – RolandasR

risposta

4

Vorrei iniziare con dead simple e semplicemente creare/drenare la piscina ad ogni passaggio del ciclo.

Se si presenta durante l'analisi delle prestazioni come un collo della bottiglia, ripararlo.

Mantenerlo semplice fino all'analisi indica la complessità è necessaria.


Ho appena riletto la tua domanda e ho realizzato qualcosa di completamente ossuto nella mia risposta. Se si sta eseguendo un ciclo di esecuzione, lo deve gestire automaticamente un pool di autoregenerazione per; dovrebbe creare un pool nella parte superiore del loop e scaricarlo alla fine di ogni passaggio attraverso il loop.

È necessario ciclarne uno solo se si hanno altri elementi in corso al di fuori del runloop. È questo il caso?

In ogni caso, sì, il modello è:

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

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

+0

+1 non dimenticare che il runloop principale di un'applicazione scarica il pool dopo ogni evento. Se Apple non pensa che sia un problema di prestazioni, probabilmente non lo è. – JeremyP

+0

Giusto per essere chiari, dovrei allocare un nuovo pool di autorelease prima del [accessoryRunLoop runMode:], e dopo averlo rilasciato? Questo è su iPhone, quindi un ambiente non GC. – Ned

0

ciclo corsa del filo principale drena la sua piscina ad ogni passaggio, quindi ha senso farlo su altri thread anche. Se si sceglie di svuotare la piscina solo occasionalmente, si rischia di avere un sacco di oggetti autoreleased in attesa di essere deallocati per un lungo periodo. Di fatto, dipende dalla quantità di memoria che è possibile rilasciare su ciascun passaggio del ciclo di esecuzione e dalla frequenza con cui si attiva il ciclo di esecuzione. Preferisco sempre scaricarlo su ogni pass solo perché è facile e mi aiuta a mantenere il footprint della memoria il più basso possibile.

0

Il modo convenzionale è, sì per mantenere un contatore e drenare ogni 50 volte o più, ma come detto bbum, basta iniziare con gocciolatoio piscina ogni ciclo, e passare da lì. O potresti -init gli oggetti di cui hai bisogno e non creare alcun oggetto autoreleased.(basta attenersi ai metodi di fabbrica) Ricorda di -release tutti i tuoi oggetti, però.

2

scolarlo ogni volta. Come altri hanno detto che il drenaggio di una piscina autorelease costa poco.

Inoltre NON lo drenaggio può essere molto costoso. Se hai abbastanza cose nel tuo pool di autorelease per causare il paging, causi l'I/O del disco e l'I/O del disco è letteralmente migliaia se non milioni di volte più costoso, quindi esegui un elenco collegato che chiama release su roba. (e su sistemi come iOS che non hanno il paging, molti oggetti extra in attesa di autorelease possono causare avvisi di memoria bassi, che potrebbero causare l'uscita forzata delle applicazioni o l'applicazione in primo piano per rilasciare una serie di viste Nib o qualcosa del genere , quindi deve ricrearlo in un secondo momento ... o potrebbe semplicemente forzare l'uscita della tua applicazione).

Anche se non si utilizza "sufficiente" memoria aggiuntiva per causare avvisi di memoria insufficiente o impaginazione, verrà eseguito un elenco di articoli di staler più grande da scaricare. Altri accessi alla memoria saranno tra il tuo nuovo articolo di autorelease e il più vecchio. C'è una possibilità molto maggiore che il più vecchio elemento di autorelease sia ora più lontano nella gerarchia di memoria, quindi la tua versione potrebbe avere errori di cache rispetto a un hit della cache L1 o L2. Quindi forse 100 volte più costoso. Inoltre, la memoria che avresti rilasciato (e potrebbe essere stata calda nella cache) potrebbe essere stata riutilizzata da un altro oggetto.

Così facendo, la procedura di autorelease ogni 50 o 100 volte potrebbe non essere nemmeno l'ottimizzazione prematura.

Effettua un rilascio per ciclo, quindi se viene visualizzato come collo di bottiglia, esegui ogni X volte, e assicurati che sia più veloce non più lento.