pub type ServerAllocator = MiMalloc;Expand description
The allocator every gunnar that serves is built on.
A #[global_allocator] is the executable’s to choose — bench’s
stages.rs says so in its own header, and cargo enforces it: two of them in
one binary is a hard error. So this crate does not install one. It publishes
the choice as a type, and each serving binary spends one line on the
declaration:
#[global_allocator]
static ALLOC: gunnar_server::ServerAllocator = gunnar_server::SERVER_ALLOCATOR;That is one implementation applied to the heap with the grain of the language rather than
against it. The choice lives in exactly one place, so the appliance, the
gunnar-solo/gunnar-service builds and the bench’s git-store-serve
cannot drift onto different allocators — and bench’s counting probes,
which must install a wrapper of their own, wrap this rather than System,
so alloc_mib_* describes the allocator that actually ships. Installing it
in the library instead looks tidier for exactly as long as it takes someone
to build a probe: it collided with stage-probe’s CountingAlloc on the
first compile.
The type is defined either way — System when the feature is off — so no
declaration site needs a #[cfg].
§Why, with the numbers
znippy’s resolver used to retain its whole read arena. Freeing it
(znippy 0f14d9b) took anon-after-seed from 4481 MB to 438 MB and
cost 78% on clone CPU — 1.47 s to 2.62 s on a 352 396-object clone.
The obvious reading is that the eviction forces re-resolution. It does
not; the clone path never calls the resolver. The retained arena was an
accidental pre-warmed malloc pool for the clone’s own ~2 GB of
allocations, and giving it back put glibc’s malloc on the critical path
for every clone thereafter. Bisected: a build that frees but does not
refcount reproduces the whole regression, so the cost is the not-leaking,
not the counting.
Four-way grid, one box, interleaved, quiet, steady state:
| resolver | allocator | clone CPU | anon after seed |
|---|---|---|---|
| leaking | glibc | 1.47 s | 4481 MB |
| freeing | glibc | 2.62 s | 438 MB |
| leaking | mimalloc | 1.18 s | 1767 MB |
| freeing | mimalloc | 1.17 s | 701 MB |
The last row beats the leaking build’s best cell on both axes at once,
and with a competent allocator the two resolvers are within 0.01 s — the
regression was never in znippy. It is user-space allocator cost and not
page faults: system time is identical (0.14 s) and suppressing trim with
M_TOP_PAD removed 20 762 faults while moving CPU by 0.04 s.
Opt out with --no-default-features; see this crate’s manifest for what
that buys and what the dependency budget does and does not actually forbid.
Aliased Type§
pub struct ServerAllocator;