Show HN: Gogc98 – live visualisation of the go allocator and GC

michaelmure1 pts0 comments

GitHub - MichaelMure/gogc98: Visualize the golang allocator and GC with the experience of a Win98 defragmenter · GitHub

/" data-turbo-transient="true" />

Skip to content

Search/

Sign in<br>Sign upAppearance settings

You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.

Dismiss alert

{{ message }}

MichaelMure

gogc98

Public

Notifications<br>You must be signed in to change notification settings

Fork

Star

master

BranchesTags

Go to file

CodeOpen more actions menu

Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit

History<br>9 Commits<br>9 Commits

.github/workflows

.github/workflows

demo

demo

probe

probe

static

static

.gitignore

.gitignore

.goreleaser.yaml

.goreleaser.yaml

LICENSE

LICENSE

README.md

README.md

embed.go

embed.go

frame.go

frame.go

go.mod

go.mod

go.sum

go.sum

main.go

main.go

state.go

state.go

View all files

Repository files navigation

gogc98

Visualize the work of the go allocator and GC managing the heap of a live go process. See allocations happening live and the GC reclaiming space.

Fill that void you had in your life since you couldn't watch the Windows 98 defragmenter operate anymore.

How it works

Go has had for a while extensive tracing in its runtime that can be<br>enabled through the GODEBUG environment variable. While this is meant<br>to be used for debugging, it can also be used for much sillier things<br>like tracking all allocations and GC activity. The other notable part<br>is flight recorder, a sort of ring<br>buffer that records those traces, ready to be shipped out of process.

gogc98 is a small bridge process that polls a target Go program over<br>HTTP for periodic flight recorder trace snapshots, decodes the<br>traceallocfree runtime experiment's alloc/free/span events plus GC<br>cycle boundaries out of them, and serves a live model of the heap over<br>a websocket to a plain HTML/Canvas frontend.

The target program only needs one line of instrumentation (see below)<br>and one environment variable — everything else runs out-of-process.<br>While the flight recorder minimizes the allocations due to observing<br>those events, recording every single allocation is somewhat expensive.

This is meant as a silly educational tool. I'd suggest not using it<br>in production.

Quick start with the demo program

Requires Go 1.26+.

cd demo<br>make run<br># open http://127.0.0.1:8080

This builds and runs both the bundled demo program (an allocation<br>generator) and the gogc98 bridge/visualizer against it.

Using gogc98 in your own program

First, install the visualizer:

go install github.com/MichaelMure/gogc98@latest

Or grab a prebuilt binary from the releases page.

Two ways to instrument a program:

Option 1: import the probe package<br>probe.Start() starts an in-process flight recorder and serves its<br>latest snapshot over HTTP — one goroutine, no other setup.

import "github.com/MichaelMure/gogc98/probe"

func main() {<br>go probe.Start()<br>// ... your program ...

go get github.com/MichaelMure/gogc98/probe

probe is its own Go module, separate from the bridge/visualizer —<br>pulling it in doesn't drag in the visualizer's own dependencies<br>(golang.org/x/exp/trace, golang.org/x/net), just runtime/trace<br>and net/http from the standard library.

The process must be launched with GODEBUG=traceallocfree=1 set<br>in its environment — the Go runtime reads GODEBUG before any Go<br>code runs, including init(), so this can't be set from within the<br>program itself. probe.Start() checks for it and exits with a clear<br>error if it's missing.

GODEBUG=traceallocfree=1 go run .

Then run the bridge against it — no need to clone this repo first,<br>go run fetches and runs it directly (defaults already match<br>probe.Addr, so no flags are actually required):

go run github.com/MichaelMure/gogc98@latest -target http://127.0.0.1:7999/snapshot

Option 2: copy the minimal code<br>If you'd rather not take the dependency, this is the entire package —<br>paste it into your own code:

import (<br>"log"<br>"net/http"<br>"runtime/trace"<br>"time"

func startGogc98Probe() {<br>fr := trace.NewFlightRecorder(trace.FlightRecorderConfig{<br>MinAge: 200 * time.Millisecond,<br>MaxBytes: 8 20,<br>})<br>if err := fr.Start(); err != nil {<br>log.Fatal("gogc98 probe: starting flight recorder: ", err)

mux := http.NewServeMux()<br>mux.HandleFunc("/snapshot", func(w http.ResponseWriter, r *http.Request) {<br>if _, err := fr.WriteTo(w); err != nil {<br>http.Error(w, err.Error(), http.StatusInternalServerError)<br>})<br>log.Print("gogc98 probe: snapshot endpoint on http://127.0.0.1:7999/snapshot")<br>log.Fatal(http.ListenAndServe("127.0.0.1:7999", mux))

Run it the same way, in its own goroutine, with the same<br>GODEBUG=traceallocfree=1 requirement as above:

func main() {<br>go startGogc98Probe()<br>// ... your program ...

GODEBUG=traceallocfree=1 go run .

License

MIT — see LICENSE.

About<br>Visualize the golang allocator and GC...

gogc98 http probe program github michaelmure

Related Articles