← Systemd memory limits calculator

How the systemd calculator works

This page walks through how the systemd calculator turns your usage data into a service's MemoryHigh and MemoryMax. Both start from the shared sizing model; this page covers what happens after that. Statements backed by the systemd or kernel documentation end with a systemd docs link to it. Choices the documentation doesn't make for us are explained and marked Assumption, which links to its row in the table of all of them.

01 What the two settings do

  • MemoryHigh is the throttling limit: above it the service's processes are heavily slowed down and memory is taken away aggressively. systemd calls it the main mechanism to control a unit's memory. systemd docs
  • MemoryMax is the absolute limit: if usage can't be kept under it, the OOM killer runs inside the unit. systemd recommends it as the last line of defense. systemd docs

They set the kernel's memory.high and memory.max. The kernel's own documentation calls memory.max the main way to limit a cgroup's memory; systemd's advice is the one the calculator follows, because it's about services. Kernel docs

There's no scheduler, so nothing reserves memory for the service: the average-based value is shown as expected usage, for reference only.

02 MemoryHigh, MemoryMax and expected usage

expected usage = average × (1 + request margin)                     rounded up to a whole M
MemoryHigh     = max(peak × (1 + limit margin), expected usage)     rounded up to a whole M
MemoryMax      = 1.25 × MemoryHigh                                   rounded up to a whole M

The margins come from the sensitivity, workload type and environment you choose; the sizing model explains them, and they are assumptions too. systemd reads the M suffix with base 1024, so M is MiB. systemd docs

  • MemoryHigh sits just above the observed peak, so normal peaks run unthrottled and throttling only starts when usage grows past anything seen so far, typically a leak. It never goes below expected usage, so a steady service isn't throttled at its normal level. Assumption
  • MemoryMax is 25% above MemoryHigh, so MemoryHigh sits 20% below it. The gap is warning time: a leak slows the service down before the kernel kills it. Neither systemd nor the cgroup v2 memory controller's own documentation gives a ratio: both treat the high limit as the main control and the max as a final safety net, which by default isn't set at all. cgroup2 docs 1.25× is ours, at the low end of what guides outside the official documentation commonly suggest: the high limit 20–30% below the max (1.25–1.43×). Assumption

Worked example

Average 295 MiB, peak 390 MiB, generic workload, medium sensitivity, production:

MemoryHigh390 MiB × 1.30 = 507 MiB507M
MemoryMax1.25 × 507 = 633.75634M
expected usage295 MiB × 1.30 = 383.5 MiB384M

A steady cache, averaging 1000 MiB with a 1020 MiB peak, where expected usage decides MemoryHigh:

expected usage1000 MiB × 1.351350M
MemoryHigh1020 MiB × 1.30 = 1326 MiB, below expected usage1350M
MemoryMax1.25 × 1350 = 1687.51688M

03 What the calculator writes

[Service]
MemoryHigh=507M
MemoryMax=634M
  • Saved as /etc/systemd/system/<service>.service.d/override.conf, it's a drop-in: systemd reads every .conf file in the unit's .service.d/ directory on top of the unit file. systemd docs Then systemctl daemon-reload && systemctl restart <service>.
  • Or, without a restart: systemctl set-property <service>.service MemoryHigh=507M MemoryMax=634M changes resource settings at runtime and keeps them for future boots. systemd docs

04 cgroup v2 only

Both settings control the memory controller of the unified hierarchy, cgroup v2. systemd docs Since systemd 258, cgroup v1 isn't supported at all. On older hosts still running it, the only setting is MemoryLimit=, deprecated since systemd 252. systemd NEWS

05 Every warning, and why

Message aboutShown whenBasis
Peak below average error The peak you entered is lower than the average Impossible with real samples; it usually means two different series. See the sizing model.

06 What to paste

container_memory_working_set_bytes{id="/system.slice/myapp.service"}
  • With cAdvisor on the host, its id label is the cgroup path, so a service is /system.slice/<name>.service. cAdvisor source
  • Without Prometheus, sample systemctl show -P MemoryCurrent myapp.service every minute and paste the bytes. MemoryCurrent reports the unit's memory.current, the cgroup's total usage, which counts page cache too; so it reads a little higher than the working set. Kernel docs systemd's documentation lists the property without describing it. Assumption

The Docker Compose guide reads the same cAdvisor working-set metric, filtered by container name instead of cgroup path.

07 All assumptions in one place

Besides the margins of the shared sizing model:

Our default: a value we chose. Our reading: how we read documentation that isn't explicit. About your setup: something we take for granted about your data or cluster.

AssumptionKindWhyIf it doesn't hold
MemoryMax is 1.25× MemoryHigh ↩Our defaultLeaves warning time between throttling and an OOM kill; no official source gives a ratioA smaller gap kills sooner after throttling starts; a larger one lets a leak take more of the host first.
MemoryHigh never goes below expected usage ↩Our defaultA steady service shouldn't be throttled at its normal levelOnly matters when peak and average are close; MemoryHigh is then a little higher.
MemoryCurrent is the unit's memory.current ↩Our readingsystemd lists the property without describing itIf it counted less than memory.current, the values would be too small.

Values you can change

The calculator’s Advanced: margins and defaults section, closed by default, lets you replace these values when your setup differs. Each field’s “?” says how it moves the result; a value outside the range is used at its nearest end, and “Reset to defaults” puts them all back.

ValueDefaultRangeWhere the default comes from
Request marginfrom the profile0–200%MemoryLimit’s default, from sensitivity, workload type and environment (sizing model); sizes expected usage
Limit marginfrom the profile0–200%MemoryLimit’s default, from sensitivity, workload type and environment (sizing model); sizes MemoryHigh
MemoryMax ratio1.25 × MemoryHigh1–2×Our default, assumption 1; guides outside the official documentation suggest 1.25–1.43

08 References

← Back to the systemd calculator