16

Stavo leggendo la documentazione di Apple sulla gestione della memoria quando sono arrivato a blocchi di pool di autorelease e qualcosa mi ha fatto riflettere.blocchi di pool autorilease iOS

Any object sent an autorelease message inside the autorelease pool block is 
released at the end of the block. 

Non sono sicuro di aver capito pienamente questo. Qualsiasi oggetto creato all'interno di un blocco pool di autorelease viene rilasciato alla fine del blocco in ogni caso perché è la sua durata. Perché dovresti chiamare autorelease sull'oggetto quando verrà rilasciato comunque quando raggiungerà la fine del blocco?

Per essere più chiaro, io darò un esempio, di quello che penso:

@autoreleasepool { 

    MyObject *obj = [[MyObject alloc] init]; // no autorelease call here 

    /* use the object*/ 
    //.... 
    // in the end it should get deallocated because it's lifespan ends, right? 
    // so why do we need to call autorelease then?! 
    } 

PS: Per favore non mi si venga a dire che a causa della ARC non abbiamo bisogno di fare alcune cose perché ARC si prende cura di loro. Ne sono pienamente consapevole, ma voglio lasciare ARC solo per qualche istante per capire il meccanismo di gestione della memoria.

risposta

27

Autorelease rimuove semplicemente un conteggio di ritenzione dall'oggetto non "libera" la memoria immediatamente come in c. Quando il pool di autorelease termina, tutti gli oggetti auto rilasciati con un conteggio pari a 0 avranno la loro memoria liberata.

A volte si creano molti oggetti. Un esempio potrebbe essere un ciclo che crea nuove stringhe ogni volta che itera e aggiunge nuovi dati alla stringa. Potresti non aver bisogno delle versioni precedenti della stringa e vorrai liberare memoria usata da quelli. È possibile farlo utilizzando esplicitamente il pool di autorelease anziché attendere che venga eseguito in modo naturale.

//Note: answers are psudocode 

//Non Arc Env 
@autoreleasepool 
{ 

    MyObject *obj = [[MyObject alloc] init]; // no autorelease call here 
    //Since MyObject is never released its a leak even when the pool exits 

} 
//Non Arc Env 
@autoreleasepool 
{ 

    MyObject *obj = [[[MyObject alloc] init] autorelease]; 
    //Memory is freed once the block ends 

} 
// Arc Env 
@autoreleasepool 
{ 

    MyObject *obj = [[MyObject alloc] init]; 
    //No need to do anything once the obj variable is out of scope there are no strong pointers so the memory will free 

} 

// Arc Env 
MyObject *obj //strong pointer from elsewhere in scope 
@autoreleasepool 
{ 

    obj = [[MyObject alloc] init]; 
    //Not freed still has a strong pointer 

} 
+0

quindi come va questa risposta alla mia domanda? Ho fornito un semplice esempio solo per evitare risposte come questa che non hanno molto a che fare con la domanda.Ho anche aggiunto commenti al piccolo esempio. – Teo

+1

In genere si utilizzano i pool di autorelease solo in una funzione in cui è presente un elevato utilizzo di memoria e ne è necessario liberare prima del normale. Il paragrafo intendeva aggiungere contesto. – Kibitz503

+0

Ok, quindi su un env non ARC, '' MyObject * obj = [[MyObject alloc] init]; '' all'interno di un pool di autorelease ci sarebbe una perdita di memoria ma su un env ARC, il compilatore aggiunge automaticamente una chiamata di rilascio per oggetto o perché non è più una perdita di memoria? – Teo

6

(. Per lo più solo dare qualche informazione supplementare; @ Kibitz503 si è sempre alla risposta giusta)

@autoreleasepool { 

    MyObject *obj = [[MyObject alloc] init]; // no autorelease call here 

    /* use the object*/ 
    //.... 
    // in the end it should get deallocated because it's lifespan ends, right? 
    // so why do we need to call autorelease then?! 
} 

PS: Per favore non mi dica che a causa della ARC noi don' Ho bisogno di fare alcune cose perché ARC si prende cura di loro. Ne sono pienamente consapevole, ma voglio lasciare ARC solo per qualche istante per capire il meccanismo di gestione della memoria.

OK, non consideriamo ARC. In quanto sopra, senza ARC, obj non sarebbe stato deallocato. Solo perché ARC aggiunge ulteriori release chiamate possibilmente get deallocated (dato il tuo esempio, in realtà non abbiamo idea dato che non sappiamo cosa succede in use the object).

Come spiega @ Kibitz503, "release" non significa "deallocate". Alla fine del blocco, il pool di autorelease viene scaricato, il che significa che tutte le chiamate in attesa autorelease vengono inviate come release alla fine del blocco. Se questo porta all'oggetto che raggiunge un conteggio di mantenimento 0, viene deallocato.

Ma se quanto sopra è in un blocco o no, senza ARC è una perdita.

+0

Buoni chiarimenti sulla perdita. È una perdita con o senza la piscina autorelease avvolta intorno ad essa! – Kibitz503

+0

Ciò significa che se utilizzo ARC e rilascio un oggetto da qualche parte al di fuori di '' @autoreleasepool {} '' l'oggetto esiste ancora fino alla fine del blocco @autoreleasepool? – confile

+0

Dipende dal codice. Alla fine del blocco autoreleasepool, vengono inviati tutti gli autoreleases in sospeso creati in quel blocco. Non so cosa significhi "rilasciare un oggetto" nel tuo esempio. Probabilmente vuoi mettere insieme un esempio di codice specifico e pubblicare una nuova domanda. –

0

Le piscine autorelease ritardano il rilascio dell'oggetto fino alla fine della piscina che evita la possibilità che venga rilasciato prima che raggiunga la fine. Quindi, in sostanza, è per assicurarsi che l'oggetto non verrà rilasciato prima della fine del pool.