GOGC and GOMEMLIMIT Calculator
Set a memory limit and GOGC may stop mattering entirely. This computes both documented target-heap rules, shows which one the runtime will use, and names the conditions — including the one where a heap near its limit collects continuously.
This is a calculator of documented behavior, not a GC simulator. It computes the two target-heap formulas the Go runtime documents and tells you which one binds. It has no allocation rate, no mark duration and no idea how long a cycle takes on your machine — so it cannot tell you your GC CPU cost, and it does not pretend to.
Nothing you enter is transmitted. There is no endpoint behind this page: the Go that does the arithmetic is compiled to WebAssembly and runs in this tab, so your numbers never leave the browser.
Start from one of these
The two rules
target heap = live heap × (1 + GOGC/100)
and, when GOMEMLIMIT is set, no more than
memory limit − everything else the runtime is holding
The runtime uses whichever is smaller. That one sentence is most of what people get wrong about these settings. A memory limit does not raise the GOGC target — it caps it. And once the cap is the smaller of the two, GOGC stops having any effect at all: you can set it to 400 and nothing moves.
What GOMEMLIMIT actually limits
The Go runtime's memory: the heap, plus goroutine stacks, plus the runtime's own structures. Not the process. Memory allocated through cgo, a mapped file, or a C library is outside it entirely, which is why a container limit set equal to GOMEMLIMIT is still exceeded by a program that uses any of them. Leave headroom.
The death spiral, and why it is a limp
When the live heap grows close to the limit, the target sits barely above it: a collection finishes with almost nowhere to grow, and the next starts almost immediately. Left alone that is a spiral — all CPU, no progress.
Go bounds it. The collector may not average more than 50% of CPU, so the program does not stop; it slows to a crawl and then, usually, runs out of memory anyway. The 50% cap is the runtime's documented behavior. The point at which this page starts warning you is a judgement about headroom, and it is labelled as one rather than presented as a threshold the runtime has.
What this deliberately does not compute
How often the GC will run, what fraction of CPU it will take, or whether a change will make your program faster. Those depend on your allocation rate and your mark cost, which are properties of your program under your load and cannot be derived from four numbers. Measure them with GODEBUG=gctrace=1 or the runtime metrics; this page tells you what the targets are, which is the part that is arithmetic.
The other tools
- Go Time Layout Converter — strftime to Go, and back — Convert a C strftime format string to a Go reference layout and back, directive by directive, with every unmappable directive named rather than guessed.
- Go Method Sets — why *T implements the interface and T does not — Paste a type and an interface and get both method sets computed by go/types, with the compiler's own error and the rule it follows from.
- Go Struct Field Alignment — offsets, padding, and what reordering saves — Paste a struct and get every field's offset, the padding between them, the total size, and a reordered version with the saving — for the architecture you choose.
- Go Slice Growth — what append actually does to the capacity — Watch a slice's capacity grow append by append: the formula's answer, the allocator's rounding, the size class it lands in, and the bytes left behind.
- Go Goroutine Dump Analyzer — read a SIGQUIT or panic stack dump — Paste a goroutine dump and get it grouped by state and by stack, with wait durations and the stacks held by far more goroutines than they should be.
- Go Benchmark Comparison — is that 4% real? — Paste two go test -bench outputs and get the Mann-Whitney U comparison: median change, p-value, and an honest answer when there is not enough data to tell.
- Go Minimal Version Selection — why that version, and who asked for it — Paste a go mod graph and see minimal version selection worked out: every version required, who required it, and the path from your main module to the requirement that won.