// Виртуальная память: статистика, адреса, страницы
// Запуск: go run vmem_demo.go

package main

import (
	"fmt"
	"os"
	"runtime"
	"unsafe"
)

func main() {
	fmt.Println("=== Go: виртуальная память ===")
	fmt.Println()

	// 1. Размер страницы
	fmt.Println("--- 1. Размер страницы ---")
	pageSize := os.Getpagesize()
	fmt.Printf("  Размер страницы: %d байт (%d КБ)\n", pageSize, pageSize/1024)
	fmt.Println()

	// 2. Адреса переменных
	fmt.Println("--- 2. Виртуальные адреса ---")
	stackVar := 42
	heapVar := new(int)
	*heapVar = 99
	fmt.Printf("  Стек:  %p\n", &stackVar)
	fmt.Printf("  Куча:  %p\n", heapVar)
	fmt.Printf("  main:  %p\n", main)
	fmt.Println("  Адреса виртуальные — ОС транслирует в физические.")
	fmt.Println()

	// 3. Статистика памяти Go
	fmt.Println("--- 3. runtime.MemStats ---")
	var stats runtime.MemStats
	runtime.ReadMemStats(&stats)
	fmt.Printf("  HeapAlloc:  %d КБ (занято объектами)\n", stats.HeapAlloc/1024)
	fmt.Printf("  HeapSys:    %d КБ (получено от ОС)\n", stats.HeapSys/1024)
	fmt.Printf("  StackSys:   %d КБ (стеки горутин)\n", stats.StackSys/1024)
	fmt.Printf("  Sys (всего): %d КБ (виртуальная память от ОС)\n", stats.Sys/1024)
	fmt.Println("  Sys >> HeapAlloc: Go резервирует виртуальную память с запасом.")
	fmt.Println()

	// 4. Go резервирует огромное виртуальное пространство
	fmt.Println("--- 4. Виртуальная память vs физическая ---")
	fmt.Println("  Go при старте резервирует десятки МБ виртуальной памяти.")
	fmt.Println("  Это не означает физическое потребление!")
	fmt.Println("  Виртуальная страница получает физический фрейм")
	fmt.Println("  только при первом обращении (demand paging).")
	fmt.Println()

	// 5. Размеры типов
	fmt.Println("--- 5. Размеры типов и выравнивание ---")
	type Example struct {
		A bool  // 1 байт
		B int64 // 8 байт
		C bool  // 1 байт
	}
	type Compact struct {
		B int64 // 8 байт
		A bool  // 1 байт
		C bool  // 1 байт
	}
	fmt.Printf("  Example{bool, int64, bool}: %d байт\n", unsafe.Sizeof(Example{}))
	fmt.Printf("  Compact{int64, bool, bool}: %d байт\n", unsafe.Sizeof(Compact{}))
	fmt.Println("  Порядок полей влияет на размер из-за выравнивания.")
	fmt.Println()

	// 6. Overcommit
	fmt.Println("--- 6. Overcommit (Linux) ---")
	fmt.Println("  malloc(1 ГБ) может вернуть указатель, даже если ОЗУ 512 МБ.")
	fmt.Println("  Linux выделяет физические страницы только при записи.")
	fmt.Println("  Если физической памяти не хватит — OOM Killer убьёт процесс.")
	fmt.Println("  macOS не делает overcommit — malloc может вернуть nil.")

	fmt.Println("\n--- Итог ---")
	fmt.Println("Виртуальная память: изоляция процессов, иллюзия большого пространства")
	fmt.Println("Demand paging: физическая память выделяется при обращении")
	fmt.Println("Go Sys >> Alloc: резервирование виртуальной памяти — не расход ОЗУ")
	fmt.Println("Overcommit (Linux): malloc \"не отказывает\", но OOM Killer рядом")
}
