// Сборка мусора: рантайм Go
// Запуск: go run gc_demo.go

package main

import (
	"fmt"
	"runtime"
	"time"
)

func main() {
	fmt.Println("=== Go: сборщик мусора ===")
	fmt.Println()

	// 1. Статистика GC
	fmt.Println("--- 1. Статистика GC ---")
	var stats runtime.MemStats
	runtime.ReadMemStats(&stats)
	fmt.Printf("  Выделено (Alloc):    %d КБ\n", stats.Alloc/1024)
	fmt.Printf("  Всего выделено:      %d КБ\n", stats.TotalAlloc/1024)
	fmt.Printf("  Сборок GC:           %d\n", stats.NumGC)
	fmt.Println()

	// 2. Выделение памяти и сборка
	fmt.Println("--- 2. Выделение и сборка ---")
	for i := 0; i < 100_000; i++ {
		_ = make([]byte, 1024) // 1 КБ, быстро становится мусором
	}
	runtime.ReadMemStats(&stats)
	fmt.Printf("  После 100K аллокаций: %d сборок GC\n", stats.NumGC)
	fmt.Printf("  Пауза последней сборки: %v\n",
		time.Duration(stats.PauseNs[(stats.NumGC+255)%256]))
	fmt.Println()

	// 3. Принудительная сборка
	fmt.Println("--- 3. runtime.GC() ---")
	before := stats.NumGC
	runtime.GC()
	runtime.ReadMemStats(&stats)
	fmt.Printf("  Сборок до: %d, после: %d\n", before, stats.NumGC)
	fmt.Printf("  Выделено после GC: %d КБ\n", stats.Alloc/1024)
	fmt.Println()

	// 4. Финализаторы
	fmt.Println("--- 4. Финализаторы ---")
	obj := &BigObject{data: make([]byte, 1024*1024), name: "BigObject-1"}
	runtime.SetFinalizer(obj, func(o *BigObject) {
		fmt.Printf("  [финализатор] %s освобождён (1 МБ)\n", o.name)
	})
	_ = obj
	obj = nil // объект становится мусором
	runtime.GC()
	runtime.GC() // финализатор может сработать не сразу
	time.Sleep(10 * time.Millisecond)
	fmt.Println("  Финализаторы ненадёжны — не используйте для ресурсов.")
	fmt.Println("  Для файлов и соединений: defer f.Close().")
	fmt.Println()

	// 5. GOGC и управление
	fmt.Println("--- 5. Настройка GC ---")
	fmt.Println("  GOGC=100 (по умолчанию): GC при удвоении кучи.")
	fmt.Println("  GOGC=50:  чаще сборки, меньше памяти.")
	fmt.Println("  GOGC=200: реже сборки, больше памяти.")
	fmt.Println("  GOGC=off: GC отключён (осторожно!).")
	fmt.Println("  GOMEMLIMIT (Go 1.19): мягкий лимит памяти.")
	fmt.Println()

	// 6. Как работает GC Go
	fmt.Println("--- 6. Алгоритм ---")
	fmt.Println("  Трёхцветная маркировка (трассировка):")
	fmt.Println("    белый = не посещён (кандидат на удаление)")
	fmt.Println("    серый  = посещён, потомки не проверены")
	fmt.Println("    чёрный = посещён, все потомки проверены")
	fmt.Println("  Конкурентный: работает параллельно с горутинами.")
	fmt.Println("  Барьер записи: перехватывает изменения указателей.")
	fmt.Println("  Паузы: < 1 мс (с Go 1.8+).")

	fmt.Println("\n--- Итог ---")
	fmt.Println("Go GC: конкурентный, трёхцветный, без поколений")
	fmt.Println("Паузы < 1 мс — приоритет над пропускной способности")
	fmt.Println("GOGC и GOMEMLIMIT — ручки настройки")
	fmt.Println("Финализаторы ненадёжны — используйте defer")
}

type BigObject struct {
	data []byte
	name string
}
