docs(findings): the 38 MiB of compiler zones is V8's optimiser, and not reachable by flags

Closes the largest unexplained item in the peak breakdown, then closes it off as a lever.

Attribution: peak_malloced_memory goes 4.5 -> 42.1 MiB the moment a board's modules
compile, while current malloced_memory stays at 1.0 - memory V8 takes to compile, frees
back to malloc, and musl never returns to the kernel. Confirmed by re-reading the
--jitless runs, where the spike never occurs at all (4.5 MiB at every stage).

--jitless is unusable because it under-renders the page, but V8 can cap the optimisation
tier instead of removing codegen. --max-opt is rejected by NODE_OPTIONS and accepted on
the command line, so it was wired behind HOMARR_MAX_OPT and A/B'd on one image:

  peak anon      276.0 -> 282.8 MiB  (+2%)
  boot idle       64.0 ->  72.3 MiB  (+13%)
  board loaded   186.1 -> 179.2 MiB  (-4%)
  4 tabs         270.8 -> 238.5 MiB  (-12%)
  after soak     199.0 -> 214.3 MiB  (+8%)
  CPU             28.1 ->  27.8 s    (unchanged)

Null result. Render integrity was verified explicitly this time - listeners 7,784 in all
four runs, DOM nodes within 40 - so unlike jitless the page rendered fully and the
comparison is valid.

The mechanism explains it: measured under --max-opt=2, peak_malloced_memory at board load
is 42.1 MiB, identical to Turbofan. Maglev's zones are just as large. Capping the tier does
not reduce zone memory; only not compiling does, and that breaks rendering.

So this 38 MiB is not reachable through V8 configuration. It scales with how much
JavaScript V8 must compile, which returns it to the single remaining server-side lever:
ship less server code. Reverted.
This commit is contained in:
Thomas Camlong committed 2026-08-10 18:43:31 +02:00
1 parent dc46057544
commit 5fb8e9223a
1 file changed
+51
+51
View File
@@ -958,6 +958,57 @@ never observes the mid-response client disconnect that creates an orphan in the
Recorded because the initial reading of the snapshot was wrong in a way that would have shipped a
fix for a leak this deployment does not have.
## The 38 MiB of compiler zones: attributed, then found to be unaddressable
The largest single item in the peak breakdown that was never explained is now explained, and then
closed off.
**It is V8's optimising compiler.** `peak_malloced_memory` jumps from 4.5 MiB to 42.1 MiB the
moment a board's modules are compiled, while *current* `malloced_memory` stays at 1.0 MiB — memory
V8 takes for compilation, frees back to malloc, and that musl never returns to the kernel. Proven
by re-reading the `--jitless` runs, where the spike **never happens at all**:
| stage | normal | `--jitless` |
| --- | --- | --- |
| boot idle | 4.5 MiB | 4.5 MiB |
| **board loaded** | **42.1 MiB** | **4.5 MiB** |
| multi-tab | 42.7 MiB | 4.5 MiB |
`--jitless` itself is unusable (it leaves the page under-rendered — see above), but V8 can cap the
*tier* instead of removing code generation: `--max-opt=3` is the default Turbofan, `2` stops at
Maglev, `1` at Sparkplug. It is rejected by `NODE_OPTIONS` but accepted on the command line, so it
was wired behind `HOMARR_MAX_OPT` and A/B'd on one image.
**`--max-opt=2` is a null result for memory:**
| stage | full | capped at Maglev |
| --- | --- | --- |
| peak anon | 276.0 MiB | 282.8 MiB (+2%) |
| boot idle | 64.0 MiB | 72.3 MiB (+13%) |
| board loaded | 186.1 MiB | 179.2 MiB (−4%) |
| 4 tabs | 270.8 MiB | 238.5 MiB (−12%) |
| after soak | 199.0 MiB | 214.3 MiB (+8%) |
| CPU | 28.1 s | 27.8 s (unchanged) |
Render integrity was checked explicitly this time, because that is how `--jitless` was caught:
listeners were **7,784 in all four runs** and DOM nodes within 40 of each other, so unlike jitless
the page rendered fully and the comparison is valid. There is simply no consistent memory win —
some stages better, some worse, peak unchanged.
The mechanism says why, and it is worth recording as a closed door. Measured directly with the
probe under `--max-opt=2`:
```
01-boot-idle peak_malloced= 4.5 MiB
03-post-login peak_malloced= 4.5 MiB
04-board-loaded peak_malloced= 42.1 MiB <- identical to Turbofan
```
**Maglev's zone allocation is just as large as Turbofan's.** Capping the tier does not reduce zone
memory; only not compiling at all does, and that breaks the page. So this 38 MiB is not reachable
through V8 configuration — it is proportional to how much JavaScript V8 has to compile, which puts
it back under the one remaining server-side lever: ship less server code. Reverted.
## jemalloc: tested, and musl is the frugal one
The largest thing that was attributed but not fixed is ~38 MiB of V8 parser/compiler zone memory