awesome-everything RU
↑ Back to the climb

Performance

GC: code and trace reading

Crux Read real Go snippets and a gctrace line, predict the GC behaviour, and pick the highest-leverage fix.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at senior altitude — in orbit
◷ 14 min

The allocation profile and the GC log are where GC problems are actually diagnosed. Read the code and the trace, then choose the fix a senior engineer would make first.

Goal

Practise the loop you run in every GC incident: read the hot path, predict where the garbage comes from, and reach for the highest-leverage fix before touching a single tuning knob.

Snippet 1 — the growing slice

func collect(rows []Row) []byte {
    var out []byte                  // nil slice, zero capacity
    for _, r := range rows {
        line := fmt.Sprintf("%d,%s\n", r.ID, r.Name)
        out = append(out, line...)  // repeatedly grows + copies
    }
    return out
}
Quiz

With 100k rows, where does most of the garbage come from, and what is the single highest-leverage fix?

Snippet 2 — the pool

var bufPool = sync.Pool{New: func() any { return new(bytes.Buffer) }}

func render(w io.Writer, v *View) error {
    b := bufPool.Get().(*bytes.Buffer)
    defer bufPool.Put(b)
    // ... write a lot into b ...
    _, err := w.Write(b.Bytes())
    return err
}
Quiz

This pooled-buffer code has a correctness bug that a load test will eventually expose. What is it?

Snippet 3 — the gctrace line

gc 488 @62.1s 39%: 0.41+352+1.1 ms clock, ... 1900->2980->1490 MB, 1990 MB goal, 8 P
Quiz

Reading this single gctrace line, which statement is correct?

Snippet 4 — escape analysis

func newPoint(x, y int) *Point {   // returns a pointer...
    p := Point{x, y}
    return &p                      // ...so p escapes to the heap
}

func sumLocal(x, y int) int {
    p := Point{x, y}               // never escapes
    return p.X + p.Y               // stays on the stack
}
Quiz

Which call allocates on the heap (adding GC work), and what is the general rule?

Recap

Every GC incident is read in code and traces: zero-capacity slices and per-iteration Sprintf are classic allocation hotspots; pooled objects must be Reset before reuse; a gctrace line tells you GC CPU share and mark time at a glance; and escape analysis decides stack vs heap based on whether a reference outlives its frame. Diagnose from the profile, fix the allocation, then re-profile to confirm.

Continue the climb ↑GC: tame a death-spiral
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.