Runtime Bootstrap
Runtime Bootstrap
Overview
Before main.main, the OS jumps into runtime startup: init the scheduler, allocator, GC metadata, threads, and package init graph. Every Go binary embeds this runtime.
Series-style depth: Understanding the Go Runtime — Bootstrap.
Diagram: from exec to main
OS loader
│
v
runtime entry (asm)
│
v
init scheduler + heap + main G
│
v
package init() order
│
v
main.main
What gets set up
| Subsystem | Early job |
|---|---|
| Allocator | arenas, spans ready for first new |
| Scheduler | GOMAXPROCS Ps, main M, main G |
| GC | metadata, write barrier off until needed |
| Signals | platform signal plumbing |
| Netpoll | poll descriptor (platform) |
Package init order
imported packages first (dependency order)
→ file-level var initializers
→ init() functions
→ main.main
Do not rely on clever cross-package init races; make dependencies explicit.
Main goroutine
main.main runs on the main goroutine. When it returns, the runtime shuts down the process (other Gs are not gracefully joined unless you waited).
Experiment
go build -o /tmp/hello .
# optional: go tool objdump / nm to see runtime symbols
go tool nm /tmp/hello | rg 'runtime\\.(main|schedinit|newproc)' | headpackage main
import "fmt"
func init() { fmt.Println("init") }
func main() { fmt.Println("main") }What to notice: init always before main; runtime symbols dominate even tiny binaries.
Try next: Compare binary size CGO_ENABLED=0 hello vs one that imports net/http.