Garbage Collection in Go
Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy — Lektion 23 von 107.
Im Gegensatz zu Sprachen wie C oder C++ verwaltet Go die Speicherverwaltung automatisch durch Garbage Collection (GC). Sie müssen den Speicher nicht manuell freigeben, wenn Sie ihn nicht mehr benötigen. Die Go-Laufzeitumgebung verfolgt, welcher Speicher noch in Gebrauch ist, und gibt den Rest wieder frei.
Wenn Sie Speicher mit new(), make() oder durch das Erstellen von Variablen zuweisen, überwacht der Garbage Collector von Go diese Allokationen. Sobald ein Wert von keinem Teil Ihres Programms mehr erreichbar ist, gibt der GC diesen Speicher automatisch frei.
func createPerson() *Person {
p := &Person{Name: "Alice", Age: 30}
return p // p entweicht auf den Heap, der GC wird es verwalten
}
func main() {
person := createPerson()
fmt.Println(person.Name)
// Wenn person nicht mehr verwendet wird, gibt der GC den Speicher wieder frei
}In diesem Beispiel wird die Person-struct auf dem Heap zugewiesen, da sie von der Funktion zurückgegeben wird. Der Go-Compiler führt eine Escape-Analyse durch, um zu bestimmen, ob eine Variable auf dem Stack bleiben kann oder auf den Heap verschoben werden muss. Der Garbage Collector verwaltet nur den Heap-Speicher.
Diese automatische Speicherverwaltung bedeutet, dass Sie sich auf die Erstellung Ihrer Anwendung konzentrieren können, ohne sich über Speicherlecks durch vergessene Deallokationen Gedanken machen zu müssen. Das Verständnis, dass GC existiert, hilft Ihnen jedoch dabei, effizienteren Code zu schreiben, indem unnötige Allokationen minimiert werden, wenn es auf die Performance ankommt.
Aufgabe
EinfachLassen Sie uns einen Session-Manager erstellen, der demonstriert, wie der Garbage Collector von Go den Speicher für Objekte verwaltet, die auf den Heap "escapen". Sie werden Sessions erstellen, die dynamisch zugewiesen und von Funktionen zurückgegeben werden, sodass der GC ihren Lebenszyklus verwaltet.
Sie werden Ihren Code auf zwei Dateien aufteilen:
session.go: Definieren Sie einSession-Struct mit den FeldernID(string),Username(string) undData(ein Slice von Strings). Erstellen Sie eineNewSession-Funktion, die eine ID und einen Benutzernamen entgegennimmt, eine neue Session auf dem Heap zuweist (indem sie einen Pointer zurückgibt) und dasData-Slice als leer initialisiert. Fügen Sie außerdem eineAddData-Methode mit einem Pointer-Receiver hinzu, die einen String an dasData-Slice der Session anhängt, sowie eineSummary-Methode, die einen formatierten String mit den Session-Details zurückgibt.main.go: Lesen Sie Session-Informationen aus der Eingabe ein, erstellen Sie eine Session mit Ihrer Konstruktor-Funktion, fügen Sie einige Dateneinträge hinzu und zeigen Sie die Session-Zusammenfassung an. Da die Session innerhalb einer Funktion erstellt und als Pointer zurückgegeben wird, "escaped" sie auf den Heap, wo der Garbage Collector sie verwalten wird.
Die folgenden Eingaben werden bereitgestellt:
- Zeile 1: Session ID
- Zeile 2: Username
- Zeile 3: Erster Dateneintrag zum Hinzufügen
- Zeile 4: Zweiter Dateneintrag zum Hinzufügen
Ihre Summary-Methode sollte einen String in diesem Format zurückgeben:
Session [ID] for user [Username]
Data entries: [count]
- [entry1]
- [entry2]Zum Beispiel, gegeben sess-001, alice, login und view_dashboard, sollte Ihre Ausgabe wie folgt aussehen:
Session sess-001 for user alice
Data entries: 2
- login
- view_dashboardDie entscheidende Erkenntnis hierbei ist, dass Ihre NewSession-Funktion eine Session erstellt und einen Pointer darauf zurückgibt. Dies führt dazu, dass die Session auf den Heap "escaped", anstatt auf dem Stack zu bleiben, wodurch sie für die Garbage Collection infrage kommt, sobald keine Referenzen mehr auf sie existieren. Ihr Code muss diesen Speicher nicht manuell freigeben – Go erledigt das automatisch.
Spickzettel
Go verwendet Garbage Collection (GC) für die automatische Speicherverwaltung. Sie müssen den Speicher nicht manuell freigeben.
Der Garbage Collector verfolgt Speicherallokationen und gibt Speicher frei, der für Ihr Programm nicht mehr erreichbar ist.
func createPerson() *Person {
p := &Person{Name: "Alice", Age: 30}
return p // p entweicht auf den Heap, GC wird ihn verwalten
}
func main() {
person := createPerson()
fmt.Println(person.Name)
// Wenn person nicht mehr verwendet wird, gibt der GC den Speicher frei
}Der Go-Compiler führt eine Escape-Analyse durch, um festzustellen, ob eine Variable auf dem Stack bleibt oder auf den Heap verschoben wird. Variablen, die auf den Heap entweichen (wie zurückgegebene Pointer), werden vom Garbage Collector verwaltet.
Der GC verwaltet nur den Heap-Speicher, nicht den Stack-Speicher. Stack-Speicher wird automatisch freigegeben, wenn eine Funktion zurückkehrt.
Probier es selbst
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Session-ID lesen
sessionID, _ := reader.ReadString('\n')
sessionID = sessionID[:len(sessionID)-1]
// Benutzernamen lesen
username, _ := reader.ReadString('\n')
username = username[:len(username)-1]
// Ersten Dateneintrag lesen
data1, _ := reader.ReadString('\n')
data1 = data1[:len(data1)-1]
// Zweiten Dateneintrag lesen
data2, _ := reader.ReadString('\n')
data2 = data2[:len(data2)-1]
// TODO: Erstelle eine neue Sitzung mit der Funktion NewSession
// Die Sitzung wird in den Heap verschoben (escape to the heap), da wir einen Pointer zurückgeben
// TODO: Füge die Dateneinträge mit der Methode AddData zur Sitzung hinzu
// TODO: Gib die Sitzungszusammenfassung mit der Methode Summary aus
fmt.Println("")
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der Go OOP
Externe DateienGo Workspace & ModulePackages & ImportsExportierte vs. nicht-exportierte NamenEinführung in OOP in GoStructs als KlassenMethoden für Structs definierenPointer- vs. Value-ReceiverStruct-InitialisierungKonstruktor-FunktionenZusammenfassung – Einfacher Taschenrechner4Interfaces
Einführung in InterfacesImplizite ImplementierungInterface als VertragLeeres Interface (any)Type AssertionType SwitchInterface-KompositionStringer & Error InterfacesRückblick - Formen-Rechner7Kapselung
Exportierte vs. nicht exportierte FelderKapselung auf Paket-EbeneGetter- & Setter-MethodenInformation Hiding in GoZusammenfassung - Studierendendatensätze10Generics (Go 1.18+)
Einführung in GenericsTypparameterType ConstraintsGenerische StructsWorkaround für generische MethodenZusammenfassung – Generische Collection2Vertiefung: Typen & Structs
Basis- & zusammengesetzte TypenBenutzerdefinierte TypdefinitionenStruct TagsAnonyme StructsVerschachtelte StructsZero Values & StandardwerteZusammenfassung - Kontaktbuch5Komposition statt Vererbung
Warum Go keine Vererbung hatGrundlagen des Struct EmbeddingMethod PromotionEinbetten mehrerer StructsEmbedding vs. AggregationShadowing eingebetteter MethodenZusammenfassung – Mitarbeiter-Hierarchie8Fehlerbehandlung & OOP
Das error-InterfaceEigene FehlertypenError Wrapping (fmt.Errorf)Sentinel-Fehlererrors.Is() und errors.As()Panic, Defer und RecoverZusammenfassung – Datei-Parser3Zeiger & Speicher
Zeiger-Grundlagen in GoZeiger auf StructsWertübergabe vs. ReferenzübergabeDie new() FunktionGarbage Collection in GoWiederholung – Linked List Builder6Polymorphismus in Go
Polymorphismus über InterfacesDuck Typing in GoInterface-ErfüllungsregelnPolymorphe CollectionsDependency InjectionZusammenfassung – Payment Processor9Nebenläufigkeit & OOP
Goroutines GrundlagenChannels & KommunikationGepufferte vs. ungepufferte ChannelsSelect-Anweisungsync.Mutex & sync.RWMutexsync.WaitGroupThread-sicheres Struct-DesignZusammenfassung - Worker Pool