Runtime#
The Go runtime is the scheduler, the garbage collector, the
allocator, and the standard libraries linked into every binary.
The compiler (go itself wraps it) produces a single static
executable; no separate VM, no shared libraries, no
LD_LIBRARY_PATH to fight.
For the toolchain that drives the
runtime (go, gofmt, go vet, dlv), see
Tooling.
The toolchain#
go is the one front-end command. The subcommands the
operator uses daily.
Command |
Effect |
|---|---|
|
Compile the current module to a single binary. |
|
Compile and run; no binary kept. |
|
Run tests in the current module. |
|
Initialise a new module. |
|
Add missing and drop unused module requirements. |
|
Add or update a dependency. |
|
Static checks for likely bugs. |
|
Format every file in place. |
|
Print docs for a package. |
Modules#
A module is a unit of versioned source; the boundary is
go.mod at its root.
$ go mod init github.com/operator/scan
$ go get github.com/spf13/cobra@latest
$ go mod tidy
go.mod records the module path, the Go version, and direct
dependencies; go.sum records hash digests for every
transitive dependency. Both files are committed.
module github.com/operator/scan
go 1.22
require (
github.com/spf13/cobra v1.8.0
golang.org/x/sync v0.7.0
)
Module paths are URLs (github.com/operator/scan,
golang.org/x/sync); the toolchain resolves them through the
module proxy (proxy.golang.org) by default.
Imports#
import "path" brings a package into scope. The package name
is the import’s last segment by convention; an alias can
override.
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/jackc/pgx/v5"
sqld "github.com/some/other/sqlite/v3" // alias to avoid collision
_ "github.com/lib/pq" // side-effect import (init only)
)
The blank-identifier import is the operator’s hook for registration patterns (database drivers, image decoders).
Cross-compilation#
The Go toolchain cross-compiles natively. GOOS picks the
target OS; GOARCH picks the architecture.
$ GOOS=linux GOARCH=amd64 go build -o scan-linux-amd64
$ GOOS=darwin GOARCH=arm64 go build -o scan-darwin-arm64
$ GOOS=windows GOARCH=amd64 go build -o scan.exe
Common matrix.
GOOS |
GOARCH |
Notes |
|---|---|---|
|
|
Standard Linux x86-64. |
|
|
Servers (Graviton, Ampere), Raspberry Pi 4/5. |
|
|
Apple Silicon. |
|
|
Intel macOS. |
|
|
Standard Windows. |
|
|
BSDs. |
CGO_ENABLED=0 produces a fully static binary (no libc); the
operator sets it for binaries that need to run inside scratch
containers or on a target without matching glibc.
$ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -ldflags="-s -w" -o scan
-s -w strips debug info; the binary shrinks noticeably.
Workspaces#
go.work lets the operator develop multiple modules together
without publishing intermediate versions.
$ go work init ./scanner ./shared
The workspace overrides module resolution for the listed modules; useful in monorepos.
Scheduler#
Go’s runtime schedules goroutines (M) onto OS threads (N) using
a work-stealing scheduler. GOMAXPROCS caps the number of OS
threads running Go code concurrently; the default is the number
of CPU cores.
$ GOMAXPROCS=4 ./service
The operator rarely tunes this; the default is right.
Garbage collection#
A concurrent tri-colour mark-sweep collector. It does
not call the GC; runtime.GC() exists for tests. GOGC
controls the trigger threshold (default 100 = collect when heap
doubles); GOMEMLIMIT sets a soft memory cap (Go 1.19+).
$ GOGC=200 ./service # collect less often, use more RAM
$ GOMEMLIMIT=2GiB ./service # cap heap+stacks+other at 2GB
runtime package#
The runtime package exposes hooks use for
profiling and debugging.
import "runtime"
runtime.NumCPU() // logical CPUs
runtime.NumGoroutine() // live goroutines (debug)
runtime.GOOS // "linux"
runtime.GOARCH // "amd64"
runtime.Version() // "go1.22.3"
var ms runtime.MemStats
runtime.ReadMemStats(&ms)
fmt.Println(ms.HeapAlloc, ms.NumGC)
For profiling, net/http/pprof (live HTTP server) or
runtime/pprof (offline files); go tool pprof reads
both.
Reflection#
reflect exposes type and value introspection at runtime.
Used by encoding/json, fmt, and generic libraries that
predate Go generics.
import "reflect"
t := reflect.TypeOf(x)
v := reflect.ValueOf(x)
for i := 0; i < t.NumField(); i++ {
fmt.Println(t.Field(i).Name, v.Field(i).Interface())
}
Avoid reflection in hot paths; the compiler generates faster code with explicit types or generics.
unsafe#
unsafe.Pointer bridges to type-erased pointers; used inside
runtime, reflect, and a handful of high-performance
libraries. Do not reach for unsafe in
application code; the cost is loss of type safety and possibly
forward-compatibility.
cgo#
import "C" calls C code from Go. Expensive in build
complexity, cross-compilation, and runtime cost; the operator
avoids it unless an existing native library is the only path.
References#
Tooling for the wider toolchain (linters, debugger, release tooling).
Concurrency for the scheduler’s user-facing surface.