SSerguey Asael Shinder
Java coding notes: the JVM, and writing software that lasts

Serguey Asael Shinder: A setting you must tune by measuring is a setting nobody tunes

· by Serguey Asael Shinder / Serguey Shinder

One sentence in JEP 545, the ZGC startup and warmup proposal now targeted to JDK 28, deserves more attention than its benchmarks. Explaining why the initial heap size is hard to choose, the JEP says that measuring its effect on startup is easy, but measuring its effect on warmup means timing many responses until they stabilise — and then: "This is rarely done in practice, so it would be best to avoid the need for such assessments in the first place."

I think that is the right way to treat a whole class of configuration.

Every system has settings whose correct value can only be found by an experiment: a pool size, a timeout, a batch size, an initial heap. Documentation then says, in effect, "measure your workload and choose". That advice is correct and almost always ignored, not because engineers are careless but because the experiment is expensive and the cost of a mediocre value is invisible. Nobody gets paged because warmup took forty seconds instead of four.

Serguey Asael Shinder: A setting you must tune by measuring is a setting nobody tunes
A setting you must tune by measuring is a setting nobody tunes — Serguey Asael Shinder

So the value that actually ships is whatever was in the first startup script, copied from the last project, or the default. In practice the default is the configuration. That makes the default the most important design decision in the feature, and "users can tune it" is not a design.

There are three honest responses when a setting needs measurement to be right:

  1. Make the default good for the common case, and say which case that is. JEP 545's answer is a 2MB initial heap plus aggressive growth, so that a small start no longer means a slow warmup.
  2. Let the system adapt at runtime to what it observes, instead of asking a human to predict it. Adaptive heap sizing is exactly this: the collector measures the allocation rate the deployer never did.
  3. If neither is possible, make the cost visible. A setting whose bad value only shows up as a slow first minute should at least log how long that minute was.

What I would avoid is the fourth option, the most common one: a knob, a paragraph of documentation, and the assumption that someone will run the experiment. When a JDK team writes down that people rarely do, it is worth believing them — and checking how many of our own settings depend on the same hope.