Sobes.tech
Middle+

Jak działa zbieracz śmieci w języku Go?

sobes.tech AI

Odpowiedź od AI

Garbage collector w Go implementuje metodę równoległą, nieprecyzyjną (non-generational), opartą na algorytmie Mark-and-Sweep z wyzwalaczem na podstawie rozmiaru sterty.

Podstawowe zasady działania:

  1. Wyzwalacz aktywacji: Kolektor uruchamia się, gdy ilość pamięci przydzielonej przez program przekracza określony próg, który jest dynamicznie regulowany.
  2. Faza oznaczania (Mark Phase):
    • Kolektor zatrzymuje tylko krytyczną część fazy oznaczania (Stop-the-World, STW), ale trwa to bardzo krótko.
    • Równolegle z działającym programem (mutator), kolektor przeszukuje graf obiektów od korzeni (rejestry, zmienne globalne, stosy gorutyn).
    • Dostępne (żywe) obiekty są oznaczane jako używane.
  3. Faza sprzątania (Sweep Phase):
    • Po zakończeniu fazy oznaczania, kolektor przechodzi przez listę zakresów pamięci (spans).
    • Nieoznaczone obiekty są uważane za śmieci i ich pamięć jest zwalniana.
    • Ta faza jest również wykonywana równolegle z działaniem programu.
  4. Bariera zapisu (Write Barrier): Go używa bariery zapisu do śledzenia zmian w grafie obiektów podczas równoległej fazy oznaczania. Zapewnia to poprawne działanie kolektora, mimo modyfikacji pamięci przez mutator.
  5. Brak pokoleń: W odróżnieniu od niektórych innych języków, Go nie dzieli obiektów na pokolenia. Kolektor obsługuje całą stertę jako całość.
  6. Cel niskiej latencji: Projektując GC w Go, dążono do minimalizacji opóźnień spowodowanych przez zbieranie śmieci (pauzy STW), co czyni go odpowiednim dla aplikacji serwerowych.

Paralelizm i użycie bariery zapisu pozwalają kolektorowi minimalizować czas zatrzymania programu, zapewniając wysoką wydajność.

Przykład uproszczonego zarządzania pamięcią (nie bezpośrednio GC, ale ilustruje zwalnianie zasobów):

package main

import (
	"fmt"
	"os"
)

func main() {
	// Przykład tworzenia tymczasowego zasobu, który będzie zwolniony
	file, err := os.Create("temp.txt")
	if err != nil {
		fmt.Println("Błąd tworzenia pliku:", err)
		return
	}
	// Opóźnione zamknięcie pliku.
	// Chociaż to nie jest GC w ścisłym tego słowa znaczeniu, demonstruje zwalnianie zasobów.
	defer file.Close()

	fmt.Println("Plik 'temp.txt' utworzony.")

	// Następnie program może pracować z plikiem...

	// GC działa automatycznie w tle, zbierając nieużywane obiekty na stercie.
	// Na przykład, jeśli utworzymy slice lub mapę:
	data := make([]int, 1000000) // Przydział na stercie
	_ = data // Użycie

	// Gdy data przestanie być osiągalne (np. po wyjściu z funkcji),
	// kolektor śmieci z czasem zwolni przydzieloną pamięć.
}