È necessario utilizzare autoreleasepool in un programma Swift?


95

A pagina 17 di questa presentazione WWDC14 , si dice

Lavorare con Objective-C? Devo ancora gestire i pool di
rilascio automatico autoreleasepool {/ * code * /}

Cosa significa? Significa che se la mia base di codice non ha file Objective-C, autoreleasepool {}non è necessario?

In una risposta a una domanda correlata , c'è un esempio in cui autoreleasepoolpuò essere utile:

- (void)useALoadOfNumbers {
    for (int j = 0; j < 10000; ++j) {
        @autoreleasepool {
            for (int i = 0; i < 10000; ++i) {
                NSNumber *number = [NSNumber numberWithInt:(i+j)];
                NSLog(@"number = %p", number);
            }
        }
    }
}

Se il codice sopra viene tradotto in Swift con autoreleasepooldrop, Swift sarà abbastanza intelligente da sapere che la numbervariabile dovrebbe essere rilasciata dopo la prima }(come fanno alcune altre lingue)?


1
Sembra che non ci sia documentazione su autoreleasepoolSwift. Ho ampliato la tua domanda e l'ho posta nei forum degli sviluppatori .
Aaron Brager

Risposte:


197

Il autoreleasepoolmodello viene utilizzato in Swift quando si restituiscono autoreleaseoggetti (creati dal codice Objective-C o utilizzando le classi Cocoa). Il autoreleasemodello in Swift funziona in modo molto simile a quello in Objective-C. Ad esempio, considera questa interpretazione rapida del tuo metodo (creazione di istanze NSImage/ UIImageoggetti):

func useManyImages() {
    let filename = pathForResourceInBundle

    for _ in 0 ..< 5 {
        autoreleasepool {
            for _ in 0 ..< 1000 {
                let image = NSImage(contentsOfFile: filename)
            }
        }
    }
}

Se lo esegui in Strumenti, vedrai un grafico delle allocazioni come il seguente:

con autoreleasepool

Ma se lo fai senza il pool di rilascio automatico, vedrai che l'utilizzo massimo della memoria è maggiore:

senza autoreleasepool

Il autoreleasepoolconsente di gestire in modo esplicito quando gli oggetti vengono deallocate autorelease a Swift, proprio come sono stati in grado di in Objective-C.

Nota: quando si ha a che fare con oggetti nativi Swift, generalmente non si riceveranno oggetti con rilascio automatico. Questo è il motivo per cui la presentazione ha menzionato l'avvertenza di averne bisogno solo quando "si lavora con Objective-C", anche se vorrei che Apple fosse più chiara su questo punto. Ma se hai a che fare con oggetti Objective-C (comprese le classi Cocoa), potrebbero essere oggetti con rilascio automatico, nel qual caso questa resa Swift del @autoreleasepoolpattern Objective-C è ancora utile.


2
Su tutte queste domande, è possibile scrivere la propria classe, e lo hanno fare un printlnin deinit, e diventa abbastanza facile verificare con precisione quando gli oggetti vengono deallocate. Oppure osservalo in Strumenti. In risposta alla tua domanda, sembra che gli oggetti Swift vengano restituiti da funzioni con un conteggio di conservazione +1 (non oggetti di rilascio automatico) e il chiamante gestirà senza problemi la proprietà da quel punto (ad esempio, se e quando l'oggetto restituito non rientra nell'ambito, viene immediatamente deallocato, non inserito in un autoreleasepool).
Rob

3
@StevenHernandez Un pool di rilascio automatico ha poco a che fare con le perdite. Una perdita è causata da un oggetto non rilasciato. Il pool di rilascio automatico, d'altra parte, è solo una raccolta di oggetti per i quali il rilascio viene posticipato fino a quando il pool non viene svuotato. I pool non controllano se qualcosa viene deallocato o meno, ma piuttosto semplicemente la tempistica di tale deallocazione. Per quanto riguarda la visualizzazione della mappa, non è possibile controllare cosa fa la memorizzazione nella cache (utilizza la memoria, ma non una vera perdita) né fare nulla se ci fosse una vera perdita (e non sono a conoscenza di alcuna perdita significativa della visualizzazione della mappa, anche se storicamente ci sono state perdite casuali e modeste in UIKit).
Rob

2
@ matt Sì, ho visto un comportamento simile. Quindi ho ripetuto il mio esercizio con NSImage/ UIImageobjects e ho manifestato il problema in modo più coerente (e, francamente, questo è un esempio più comune del problema, poiché il picco di utilizzo della memoria è spesso problematico solo quando si tratta di oggetti più grandi; un esempio pratico di questo potrebbe essere una routine che ridimensiona un mucchio di immagini). Ho anche riprodotto il comportamento chiamando il codice Objective-C che creava esplicitamente oggetti con rilascio automatico. Non fraintendetemi: penso che abbiamo bisogno di pool di rilascio automatico in Swift meno spesso che in Objective-C, ma ha ancora un ruolo da svolgere.
Rob il

1
Ho trovato un esempio che funziona! Chiama pathForResource:ofType:ripetutamente NSBundle .
matt

1
Il mio pathForResource:ofType:esempio non funziona più in Xcode 6.3 / Swift 1.2. :)
matt

4

Se lo usassi nel codice Objective-C equivalente, lo userai in Swift.

Swift sarà abbastanza intelligente da sapere che la variabile numerica dovrebbe essere rilasciata dopo la prima}

Solo se Objective-C lo fa. Entrambi operano secondo le regole di gestione della memoria Cocoa.

Ovviamente ARC sa che numberesce dall'ambito alla fine di quell'iterazione del ciclo, e se lo ha mantenuto, lo rilascerà lì. Tuttavia, questo non ti dice se l'oggetto è stato rilasciato automaticamente, perché -[NSNumber numberWithInt:] potrebbe o meno aver restituito un'istanza rilasciata automaticamente. Non c'è modo che tu possa saperlo, perché non hai accesso alla fonte di -[NSNumber numberWithInt:].


1
Se Swift si comporta come Objective-C per questo, perché la presentazione menzionava "Working with Objective-C?" nello specifico?
Ethan

9
@Ethan Sembrerebbe che gli oggetti Swift nativi non siano oggetti con rilascio automatico e il autoreleasepoolcostrutto non sia assolutamente necessario. Ma se il codice Swift gestisce oggetti Objective-C (inclusi gli oggetti Cocoa), questi seguono schemi di rilascio automatico e quindi il autoreleasepoolcostrutto diventa utile.
Rob

Ho capito che "L'autoreleasepool ti permette di gestire esplicitamente quando gli oggetti autorelease vengono deallocati in Swift" ma perché dovrei farlo? Perché il compilatore non lo fa / non può farlo per me? Ho dovuto aggiungere il mio autoreleasepool per impedire alla VM di andare alle stelle in un ciclo stretto di enormi manipolazioni di stringhe. Per me era ovvio dove aggiungere, e ha funzionato perfettamente. Perché il compilatore non poteva farlo? Il compilatore potrebbe essere reso più intelligente per fare un buon lavoro?
vonlost
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.