Назад к вопросам
Middle+
252
questionbank

Как работает сборщик мусора в языке Go?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Сборщик мусора в Go реализует параллельный, неточный (non-generational) метод, основанный на алгоритме Mark-and-Sweep с триггером по объему кучи.

Основные принципы работы:

  1. Триггер активации: Сборщик запускается, когда объем выделенной программой памяти превышает определенный порог. Этот порог динамически регулируется.
  2. Mark Phase (Фаза пометки):
    • Сборщик приостанавливает выполнение только критически важной части Mark Phase (Stop-the-World, STW), но это занимает очень короткое время.
    • Параллельно с работающей программой (mutator) сборщик обходит граф объектов из корневых указателей (регистры, глобальные переменные, стеки горутин).
    • Достижимые (живые) объекты помечаются как используемые.
  3. Sweep Phase (Фаза очистки):
    • После завершения Mark Phase, сборщик проходит по списку аренд памяти (spans).
    • Непомеченные объекты считаются мусором и их память освобождается.
    • Эта фаза также выполняется параллельно с работой программы.
  4. Write Barrier: Go использует write barrier для отслеживания изменений в графе объектов во время параллельной фазы пометки. Это гарантирует корректную работу сборщика, несмотря на модификации памяти мутатором.
  5. Нет поколений: В отличие от некоторых других языков, Go не делит объекты на поколения. Сборщик обрабатывает всю кучу целиком.
  6. Цель низкой задержки: При проектировании Go GC была поставлена задача минимизировать задержки, вызванные сборкой мусора (паузы STW), что делает его подходящим для серверных приложений.

Параллельность и использование write barrier позволяют сборщику минимизировать время остановок программы, обеспечивая высокую производительность.

Пример упрощенного управления памятью (не напрямую GC, но иллюстрирует освобождение ресурсов):

package main

import (
	"fmt"
	"os"
)

func main() {
	// Пример создания временного ресурса, который будет утилизирован
	file, err := os.Create("temp.txt")
	if err != nil {
		fmt.Println("Error creating file:", err)
		return
	}
	// Отложенное закрытие файла.
	// Хотя это не GC в чистом виде, демонстрирует освобождение ресурсов.
	defer file.Close()

	fmt.Println("File 'temp.txt' created.")

	// Далее программа может работать с файлом...

	// GC работает автоматически в фоновом режиме для сборки неиспользуемых объектов в куче.
	// Например, если создать слайс или мапу:
	data := make([]int, 1000000) // Выделение в куче
	_ = data // Использование

	// Когда data перестанет быть достижимой (например, при выходе из функции),
	// сборщик мусора со временем освободит выделенную под нее память.
}