Go Struct Field Alignment
Paste a struct and get every field's offset, the padding between them, the total size, and a reordered version with the saving — computed by go/types for the architecture you pick, not for whichever machine this happens to run on.
Nothing you paste is transmitted. There is no endpoint behind this page: the Go that computes the layout is compiled to WebAssembly and runs in this tab, so your source never leaves the browser.
This page loads the larger of the section's two modules, because it carries the compiler's own front end — go/ast, go/parser and go/types. It is fetched once, when you open the page.
Start from one of these
Where the numbers come from
Every offset, size and alignment on this page is computed by go/types — Offsetsof, Sizeof, Alignof — which is the model the compiler itself uses. Nothing about the layout rules is written down in the tool, and that is deliberate: the rules have exceptions that are easy to state wrongly, and a hand-rolled model gets those right until it does not.
The Go version that computed them is printed with the result, because the rules belong to a toolchain. A layout figure with no version beside it is a figure with no shelf life.
Why the architecture is a question
A struct's size is not a property of your source. struct{ a bool; b int64 } is 16 bytes on amd64 and 12 on 386, because an int64 needs 8-byte alignment on one and 4 on the other. A tool that answered for whatever machine it happened to run on would be confidently wrong for anyone targeting anything else, and would give no sign of it — so the target is a picker, and it is named in the answer.
The rule, and the reordering
A field of alignment a must start at an offset that is a multiple of a, so the compiler inserts padding to get there. The struct itself is aligned to the largest alignment among its fields, and its size is rounded up to a multiple of that — which is where tail padding comes from.
Sorting the fields by descending alignment removes the padding between them: alignments are powers of two, so once the running offset is a multiple of a larger power it is already a multiple of every smaller one. That is why the reordering below is optimal rather than merely better.
With one exception, which is worth knowing on its own: a zero-sized field at the end of a struct is padded. Go guarantees that the address of a field is inside the allocation, so a trailing struct{} forces an extra alignment unit. Descending alignment would put a zero-sized field last, so the tool puts them first, where they cost nothing. This was found by permuting every ordering of a test struct and comparing — not by reasoning about it.
What this deliberately does not tell you
Whether to adopt the reordering. Field order is also an API: a struct literal without field names depends on it, and so does anything reflecting over declaration order. It also affects cache behavior — two fields read together are better adjacent than merely well packed. This page reports the saving and writes out the alternative; the decision is yours.
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 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.