Garbage collection in Go
Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 23 di 107.
A differenza di linguaggi come C o C++, Go gestisce automaticamente la memoria tramite la garbage collection (GC). Non devi liberare manualmente la memoria quando hai finito di usarla. Il runtime di Go tiene traccia della memoria ancora in uso e recupera quella restante.
Quando allochi memoria usando new(), make() o creando variabili, il garbage collector di Go monitora queste allocazioni. Quando un valore non è più raggiungibile da alcuna parte del tuo programma, il GC libera automaticamente quella memoria.
func createPerson() *Person {
p := &Person{Name: "Alice", Age: 30}
return p // p viene allocato nell'heap, GC lo gestirà
}
func main() {
person := createPerson()
fmt.Println(person.Name)
// Quando person non viene più usato, GC recupera la memoria
}In questo esempio, la struct Person viene allocata nell'heap perché viene restituita dalla funzione. Il compilatore di Go esegue l'analisi della fuga per determinare se una variabile può rimanere nello stack o deve essere spostata nell'heap. Il garbage collector gestisce solo la memoria dell'heap.
Questa gestione automatica della memoria significa che puoi concentrarti sulla creazione della tua applicazione senza preoccuparti delle perdite di memoria dovute a deallocazioni dimenticate. Tuttavia, sapere che esiste il GC ti aiuta a scrivere codice più efficiente, riducendo al minimo le allocazioni non necessarie quando le prestazioni sono importanti.
Sfida
FacileCreiamo un gestore di sessioni che mostra come il garbage collector di Go gestisce la memoria degli oggetti che sfuggono all’heap. Creerai sessioni allocate dinamicamente e restituite dalle funzioni, lasciando che il GC ne gestisca il ciclo di vita.
Organizzerai il codice in due file:
session.go: Definisci una structSessioncon i campiID(string),Username(string) eData(una slice di stringhe). Crea una funzioneNewSessionche accetta un ID e un nome utente, alloca una nuova Session nell’heap (restituendo un puntatore) e inizializza la slice Data come vuota. Aggiungi anche un metodoAddDatacon un receiver puntatore che aggiunge una stringa alla slice Data della sessione, e un metodoSummaryche restituisce una stringa formattata con i dettagli della sessione.main.go: Leggi le informazioni della sessione dall’input, crea una sessione usando la funzione costruttrice, aggiungi alcune voci di dati e visualizza il riepilogo della sessione. Poiché la sessione viene creata all’interno di una funzione e restituita come puntatore, sfugge all’heap, dove sarà gestita dal garbage collector.
Verranno forniti i seguenti input:
- Riga 1: ID della sessione
- Riga 2: Nome utente
- Riga 3: Prima voce di dati da aggiungere
- Riga 4: Seconda voce di dati da aggiungere
Il metodo Summary dovrebbe restituire una stringa in questo formato:
Session [ID] for user [Username]
Data entries: [count]
- [entry1]
- [entry2]Per esempio, dati sess-001, alice, login e view_dashboard, l’output dovrebbe essere:
Session sess-001 for user alice
Data entries: 2
- login
- view_dashboardL’idea fondamentale è che la funzione NewSession crea una Session e ne restituisce un puntatore. Questo fa sì che la Session “sfugga” all’heap invece di rimanere sullo stack, rendendola idonea alla garbage collection quando non rimangono riferimenti a essa. Il tuo codice non deve liberare manualmente questa memoria: Go la gestisce automaticamente.
Provalo tu
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Leggi l'ID della sessione
sessionID, _ := reader.ReadString('\n')
sessionID = sessionID[:len(sessionID)-1]
// Leggi il nome utente
username, _ := reader.ReadString('\n')
username = username[:len(username)-1]
// Leggi la prima voce di dati
data1, _ := reader.ReadString('\n')
data1 = data1[:len(data1)-1]
// Leggi la seconda voce di dati
data2, _ := reader.ReadString('\n')
data2 = data2[:len(data2)-1]
// TODO: Crea una nuova sessione usando la funzione NewSession
// La sessione verrà allocata nello heap perché restituiamo un puntatore
// TODO: Aggiungi le voci di dati alla sessione usando il metodo AddData
// TODO: Stampa il riepilogo della sessione usando il metodo Summary
fmt.Println("")
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti di OOP in Go
File esterniWorkspace e moduli GoPacchetti e importazioniNomi esportati e non esportatiIntroduzione all’OOP in GoGli struct come classiDefinire metodi sugli structReceiver con puntatore vs receiver con valoreInizializzazione degli structFunzioni costruttriciRiepilogo - Calcolatrice semplice4Interfacce
Introduzione alle interfacceImplementazione implicitaL’interfaccia come contrattoInterfaccia vuota (any)Asserzione di tipoSwitch sul tipoComposizione di interfacceInterfacce Stringer ed ErrorRipasso - Calcolatore di forme7Incapsulamento
Campi esportati e non esportatiIncapsulamento a livello di packageMetodi Getter e SetterNascondimento delle informazioni in GoRiepilogo - Registri degli studenti10Tipi generici (Go 1.18+)
Introduzione ai tipi genericiParametri di tipoVincoli di tipoStruct genericheSoluzione alternativa per i metodi genericiRiepilogo - Collezione generica13Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneModello SingletonModello FactoryModello Abstract FactoryModello ObserverModello Strategy2Approfondimento su tipi e struct
Tipi di base e compostiDefinizioni di tipi personalizzatiTag delle structStruct anonimeStruct annidateValori zero e predefinitiRipasso - Rubrica5Composizione invece dell'ereditarietà
Perché Go non ha l'ereditarietàFondamenti dell'embedding delle structPromozione dei metodiEmbedding di più structEmbedding e aggregazione a confrontoMascheramento dei metodi embeddedRiepilogo: gerarchia dei dipendenti8Gestione degli errori e OOP
L'interfaccia errorTipi di errore personalizzatiWrapping degli errori (fmt.Errorf)Errori sentinellaerrors.Is() ed errors.As()Panic, Defer e RecoverRiepilogo - Parser di file11Libreria standard e OOP
io.Reader e io.Writersort.InterfaceInterfaccia fmt.Stringerencoding/json con le structInterfaccia http.HandlerRipasso - modelli REST API14Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeMiddleware come Decorator3Puntatori e memoria
Concetti base dei puntatori in GoPuntatori a structPassaggio per valore vs per riferimentoLa funzione new()Garbage collection in GoRiepilogo - Costruttore di liste concatenate6Polimorfismo in Go
Polimorfismo tramite interfacceDuck typing in GoRegole di soddisfacimento delle interfacceCollezioni polimorficheIniezione delle dipendenzeRiepilogo - Elaboratore di pagamenti9Concorrenza e OOP
Basi delle goroutineCanali e comunicazioneCanali bufferizzati vs non bufferizzatiIstruzione selectsync.Mutex e sync.RWMutexsync.WaitGroupProgettazione di struct thread-safeRiepilogo: worker poolEsercitati da solo: Compilatore Go online