Odśmiecanie pamięci w Go
Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 23 z 107.
W przeciwieństwie do języków takich jak C czy C++, Go automatycznie zarządza pamięcią za pomocą automatycznego odzyskiwania pamięci (GC). Nie musisz ręcznie zwalniać pamięci, gdy przestajesz jej używać. Środowisko uruchomieniowe Go śledzi, która pamięć jest nadal używana, i odzyskuje pozostałą.
Gdy przydzielasz pamięć za pomocą new(), make() lub przez tworzenie zmiennych, garbage collector Go monitoruje te przydziały. Gdy żadna część programu nie może już uzyskać dostępu do danej wartości, GC automatycznie zwalnia tę pamięć.
func createPerson() *Person {
p := &Person{Name: "Alice", Age: 30}
return p // p trafia na stertę, GC będzie nim zarządzać
}
func main() {
person := createPerson()
fmt.Println(person.Name)
// Gdy person nie jest już używany, GC odzyskuje pamięć
}W tym przykładzie struktura Person jest alokowana na stercie, ponieważ jest zwracana z funkcji. Kompilator Go przeprowadza analizę ucieczki, aby określić, czy zmienna może pozostać na stosie, czy musi zostać przeniesiona na stertę. Garbage collector zarządza wyłącznie pamięcią sterty.
To automatyczne zarządzanie pamięcią oznacza, że możesz skupić się na tworzeniu aplikacji bez obaw o wycieki pamięci spowodowane zapomnianym zwalnianiem pamięci. Jednak świadomość istnienia GC pomaga pisać wydajniejszy kod dzięki ograniczaniu niepotrzebnych alokacji, gdy wydajność ma znaczenie.
Wyzwanie
ŁatwyZbudujmy menedżera sesji, który pokazuje, jak garbage collector w Go zarządza pamięcią obiektów, które trafiają na stertę. Utworzysz sesje przydzielane dynamicznie i zwracane z funkcji, dzięki czemu GC będzie zarządzać ich cyklem życia.
Rozmieścisz swój kod w dwóch plikach:
session.go: Zdefiniuj strukturęSessionz polamiID(string),Username(string) iData(slice ciągów znaków). Utwórz funkcjęNewSession, która przyjmuje ID i nazwę użytkownika, przydziela nową sesję na stercie (zwracając wskaźnik) i inicjuje pusty slice Data. Dodaj też metodęAddDataz odbiornikiem wskaźnikowym, która dopisuje ciąg znaków do slice Data sesji, oraz metodęSummary, która zwraca sformatowany ciąg znaków zawierający szczegóły sesji.main.go: Odczytaj informacje o sesji z wejścia, utwórz sesję za pomocą funkcji konstruktora, dodaj do niej kilka wpisów danych i wyświetl podsumowanie sesji. Ponieważ sesja jest tworzona wewnątrz funkcji i zwracana jako wskaźnik, trafia na stertę, gdzie będzie nią zarządzać garbage collector.
Podane zostaną następujące dane wejściowe:
- Wiersz 1: ID sesji
- Wiersz 2: Nazwa użytkownika
- Wiersz 3: Pierwszy wpis danych do dodania
- Wiersz 4: Drugi wpis danych do dodania
Metoda Summary powinna zwracać ciąg znaków w następującym formacie:
Session [ID] for user [Username]
Data entries: [count]
- [entry1]
- [entry2]Na przykład dla danych sess-001, alice, login i view_dashboard wynik powinien wyglądać następująco:
Session sess-001 for user alice
Data entries: 2
- login
- view_dashboardKluczowa kwestia jest taka, że funkcja NewSession tworzy sesję i zwraca wskaźnik do niej. Powoduje to, że sesja „ucieka” na stertę, zamiast pozostać na stosie, dzięki czemu może zostać usunięta przez garbage collector, gdy nie pozostaną już do niej żadne referencje. Twój kod nie musi ręcznie zwalniać tej pamięci: Go robi to automatycznie.
Spróbuj swoich sił
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Odczytaj identyfikator sesji
sessionID, _ := reader.ReadString('\n')
sessionID = sessionID[:len(sessionID)-1]
// Odczytaj nazwę użytkownika
username, _ := reader.ReadString('\n')
username = username[:len(username)-1]
// Odczytaj pierwszy wpis danych
data1, _ := reader.ReadString('\n')
data1 = data1[:len(data1)-1]
// Odczytaj drugi wpis danych
data2, _ := reader.ReadString('\n')
data2 = data2[:len(data2)-1]
// TODO: Utwórz nową sesję za pomocą funkcji NewSession
// Sesja trafi na stertę, ponieważ zwracamy wskaźnik
// TODO: Dodaj wpisy danych do sesji za pomocą metody AddData
// TODO: Wypisz podsumowanie sesji za pomocą metody Summary
fmt.Println("")
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy OOP w Go
Pliki zewnętrzneObszar roboczy i moduły GoPakiety i importyNazwy eksportowane i nieeksportowaneWprowadzenie do OOP w GoStruktury jako klasyDefiniowanie metod dla strukturOdbiorniki wskaźnikowe i wartościoweInicjalizacja strukturFunkcje konstruktoraPodsumowanie – prosty kalkulator4Interfejsy
Wprowadzenie do interfejsówImplementacja niejawnaInterfejs jako kontraktPusty interfejs (any)Asercja typuPrzełącznik typówKompozycja interfejsówInterfejsy Stringer i ErrorPowtórka — kalkulator figur7Hermetyzacja
Pola eksportowane i nieeksportowaneHermetyzacja na poziomie pakietuMetody pobierające i ustawiająceUkrywanie informacji w GoPowtórka – dane studentów10Typy generyczne (Go 1.18+)
Wprowadzenie do typów generycznychParametry typówOgraniczenia typówStruktury generyczneObejście ograniczeń metod generycznychPodsumowanie — generyczna kolekcja2Typy i struktury w praktyce
Typy proste i złożoneDefiniowanie własnych typówTagi pól strukturStruktury anonimoweStruktury zagnieżdżoneWartości zerowe i domyślnePodsumowanie – książka kontaktów5Kompozycja zamiast dziedziczenia
Dlaczego Go nie ma dziedziczeniaPodstawy osadzania strukturPromowanie metodOsadzanie wielu strukturOsadzanie a agregacjaPrzesłanianie osadzonych metodPodsumowanie — hierarchia pracowników8Obsługa błędów i programowanie obiektowe
Interfejs błęduWłasne typy błędówOpakowywanie błędów (fmt.Errorf)Błędy wartowniczeerrors.Is() i errors.As()Panic, Defer i RecoverPodsumowanie — parser plików3Wskaźniki i pamięć
Podstawy wskaźników w GoWskaźniki do strukturPrzekazywanie przez wartość a przez referencjęFunkcja new()Odśmiecanie pamięci w GoPowtórka — kreator listy wiązanej6Polimorfizm w Go
Polimorfizm za pomocą interfejsówDuck typing w GoZasady spełniania interfejsówKolekcje polimorficzneWstrzykiwanie zależnościPowtórka — procesor płatności9Współbieżność i OOP
Podstawy goroutinesKanały i komunikacjaKanały buforowane i niebuforowaneInstrukcja selectsync.Mutex i sync.RWMutexsync.WaitGroupProjektowanie struktur bezpiecznych wątkowoPowtórka – pula workerów12Zaawansowane zagadnienia programowania obiektowego
Wzorzec opcji funkcyjnychWzorzec Builder w GoŁańcuchowe wywoływanie metodAliasy typów a definicje typówPodstawy refleksjiPrzegląd generowania koduPoćwicz samodzielnie: Kompilator Go online