Come funziona il pool di autorelease NSAutoreleasePool?

A quanto ho capito, tutto ciò che è stato creato con allocazioni , nuove o copie deve essere rilasciato manualmente. Per esempio:

int main(void) { NSString *string; string = [[NSString alloc] init]; /* use the string */ [string release]; } 

La mia domanda, però, non sarebbe così valida ?:

 int main(void) { NSAutoreleasePool *pool; pool = [[NSAutoreleasePool alloc] init]; NSString *string; string = [[[NSString alloc] init] autorelease]; /* use the string */ [pool drain]; } 

Sì, il tuo secondo snippit di codice è perfettamente valido.

Ogni volta che un’autorelease viene inviato a un object, viene aggiunto al pool di autorelease più interno. Quando il pool viene scaricato, invia semplicemente -release a tutti gli oggetti nel pool.

I pool di autorelease sono semplicemente una comodità che consente di posticipare l’invio -release fino a “dopo”. Quel “più tardi” può accadere in diversi punti, ma il più comune nelle app della GUI di Cocoa è alla fine del ciclo del ciclo di esecuzione corrente.

NSAutoreleasePool: drain vs. release

Poiché la funzione di drain e release sembra causare confusione, potrebbe valere la pena chiarire qui (sebbene questo sia coperto nella documentazione …).

A rigor di termini, dal punto di vista della prospettiva il drain non è equivalente al release :

In un ambiente conteggiato di riferimento, drain esegue le stesse operazioni del release , quindi i due sono in questo senso equivalenti. Per sottolineare, questo significa che non si perde una piscina se si utilizza lo drain piuttosto che il release .

In un ambiente garbage-collected, il release è un no-op. Quindi non ha alcun effetto. drain , d’altra parte, contiene un suggerimento al collezionista che dovrebbe “raccogliere se necessario”. Pertanto, in un ambiente garbage-collected, l’utilizzo di drain aiuta gli sweep di raccolta del saldo di sistema.

Come già sottolineato, il tuo secondo snippet di codice è corretto.

Vorrei suggerire un modo più succinto di utilizzare il pool di autorelease che funziona su tutti gli ambienti (conteggio ref, GC, ARC) ed evita anche la confusione di scarico / rilascio:

 int main(void) { @autoreleasepool { NSString *string; string = [[[NSString alloc] init] autorelease]; /* use the string */ } } 

Nell’esempio sopra, si noti il ​​blocco @autoreleasepool . Questo è documentato qui .

No, ti sbagli. La documentazione afferma chiaramente che, in assenza di GC, -drain è equivalente a -release, il che significa che NSAutoreleasePool non sarà trapelato.

Ho trovato questo collegamento ha fornito la migliore spiegazione su quando e come utilizzare NSAutoReleasePool: AutoReleasePool

sì il tuo codice è perfetto, se dovessi usare la raccolta dei rifiuti sarebbe sufficiente impostare la stringa su zero quando hai finito. La raccolta dei rifiuti non è buona per le prestazioni della tua app, quindi non la consiglierei di usarla: P

Quello che ho letto da Apple: “Alla fine del blocco pool di autorilease, agli oggetti che hanno ricevuto un messaggio di autorelease all’interno del blocco viene inviato un messaggio di rilascio: un object riceve un messaggio di rilascio per ogni volta che è stato inviato un messaggio di autorelease all’interno del blocco. ”

https://developer.apple.com/library/mac/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html

l’invio di autorelease anziché di rilascio a un object estende la durata di tale object almeno finché il pool stesso non viene scaricato (potrebbe essere più lungo se l’object viene successivamente mantenuto). Un object può essere inserito nello stesso pool più volte, nel qual caso riceve un messaggio di rilascio per ogni volta che è stato inserito nel pool.

Sì e no. Si finirebbe con il rilasciare la memoria delle stringhe ma “si perde” l’object NSAutoreleasePool in memoria utilizzando drain anziché release se si è eseguito questo in un ambiente garbage collection (non gestito dalla memoria). Questa “perdita” rende semplicemente l’istanza di NSAutoreleasePool “irraggiungibile” come qualsiasi altro object senza puntatori forti in GC, e l’object verrebbe ripulito alla prossima esecuzione di GC, che potrebbe benissimo essere subito dopo la chiamata a -drain :

drenare

In un ambiente garbage collocato, triggers la garbage collection se la memoria allocata dall’ultima raccolta è maggiore della soglia corrente; altrimenti si comporta come una versione. … In un ambiente garbage-collected, questo metodo in definitiva chiama objc_collect_if_needed .

Altrimenti, è simile al comportamento di come -release sotto non-GC, sì. Come altri hanno affermato, -release è un no-op sotto GC, quindi l’unico modo per assicurarsi che il pool funzioni correttamente sotto GC è attraverso -drain , e -drain sotto non-GC funziona esattamente come -release sotto non-GC, e probabilmente comunica anche la sua funzionalità in modo più chiaro.

Dovrei sottolineare che la tua affermazione “qualsiasi cosa chiamata con new, alloc o init” non dovrebbe includere “init” (ma dovrebbe includere “copy”), perché “init” non alloca memoria, imposta solo l’object (costruttore moda). Se hai ricevuto un object alloc’d e la tua funzione ha chiamato solo init come tale, non la rilascerai:

 - (void)func:(NSObject*)allocd_but_not_init { [allocd_but_not_init init]; } 

Ciò non consuma più memoria di quella con cui hai già iniziato (supponendo che init non istanzia gli oggetti, ma non sei comunque responsabile per quelli).