2015-02-10 14 views
11

Se implemento una coda così ...I rifiuti vanno raccolti parti di fette?

package main 

import(
    "fmt" 
) 

func PopFront(q *[]string) string { 
    r := (*q)[0] 
    *q = (*q)[1:len(*q)] 
    return r 
} 

func PushBack(q *[]string, a string) { 
    *q = append(*q, a) 
} 

func main() { 
    q := make([]string, 0) 

    PushBack(&q, "A") 
    fmt.Println(q) 
    PushBack(&q, "B") 
    fmt.Println(q) 
    PushBack(&q, "C") 
    fmt.Println(q) 

    PopFront(&q) 
    fmt.Println(q) 
    PopFront(&q) 
    fmt.Println(q)  
} 

... io alla fine con un array ["A", "B", "C"] che non ha fette rivolte verso i primi due elementi. Poiché il puntatore "start" di una porzione non può mai essere decrementato (AFAIK), non è mai possibile accedere a tali elementi.

Il bidone della spazzatura di Go è abbastanza intelligente da liberarli?

risposta

17

Le fette sono solo descrittori (piccole strutture di dati simili a strutture) che, se non referenziate, verranno raccolte correttamente.

La matrice sottostante per una fetta (a cui punta descrittore a) invece è condivisa tra tutte le sezioni che vengono creati dai reslicing esso: citando la Go Language Specification: Slice Types:

Una fetta, una volta inizializzato, è sempre associato a una matrice sottostante che contiene i suoi elementi. Una slice quindi condivide lo storage con la sua matrice e con altre slice della stessa matrice; al contrario, gli array distinti rappresentano sempre una memoria distinta.

Pertanto, se almeno una sezione esiste o una variabile nell'array se una sezione è stata creata affettando l'array, non sarà raccolto.

Ufficiale Dichiarazione su questo:

Il post sul blog Go Slices: usage and internals Con Andrew Gerrand afferma chiaramente questo comportamento:

Come accennato in precedenza, ri-tagliare una fetta non fa una copia del matrice sottostante. L'array completo verrà mantenuto in memoria fino a quando non viene più fatto riferimento. Occasionalmente questo può far sì che il programma tenga tutti i dati in memoria quando è necessario solo un piccolo frammento di esso.

...

Poiché la fetta riferimento dell'array originale, finché la porzione viene mantenuto intorno al garbage collector non può rilasciare la matrice.

Torna al tuo esempio

Mentre la matrice sottostante non verrà liberata, si noti che se si aggiungono nuovi elementi alla coda, il built-in append funzione di tanto in tanto potrebbe allocare un nuovo array e copiare gli elementi attuali al nuovo - ma la copia copierà solo gli elementi della slice e non l'intero array sottostante! Quando si verifica una tale riallocazione e copia, la matrice "vecchia" può essere raccolta tramite spazzatura se non esiste alcun altro riferimento.

Un'altra cosa molto importante è che se un elemento viene estratto dalla parte anteriore, la slice verrà riscritta e non conterrà un riferimento all'elemento popped, ma poiché l'array sottostante contiene ancora quel valore, il valore resterà anche in memoria (non solo l'array).Si consiglia che ogni volta che un elemento viene scoppiato o rimosso dalla coda (slice/array), lo azzeri sempre a (il suo rispettivo elemento nella sezione) in modo che il valore non rimanga nella memoria inutilmente. Ciò diventa ancora più critico se la tua sezione contiene puntatori a strutture di grandi dimensioni.

func PopFront(q *[]string) string { 
    r := (*q)[0] 
    (*q)[0] = "" // Always zero the removed element! 
    *q = (*q)[1:len(*q)] 
    return r 
} 
+7

Per completare icza risposta, e per il tuo particolare caso in coda: la parte non raggiungibile della slice non sarà raccolta in background, tuttavia, quando "PushBack' un nuovo elemento e' q' è già pieno, verrà assegnata una nuova copia di 'q', e in questo caso, verranno ** copiati solo ** elementi raggiungibili **, quindi A, B e C non lo faranno. 'q' non crescerà per sempre con elementi irraggiungibili. – siritinga

+0

@siritinga È vero, buon suggerimento. Grazie. Incorporato nella risposta con ulteriori informazioni importanti (come azzerare lo "slot" se un elemento viene rimosso). – icza

0

semplice domanda, risposta semplice: No. (. Ma se continuare a spingere la fetta a un certo punto troppo pieno la sua gamma di fondo quindi gli elementi inutilizzati resi disponibili per essere liberati)

Problemi correlati