Skip to main content

CPU and memory limits for a service: cgroups v2, systemd

VDS / VPS · 09.11.2026 · 6 min read

What cgroups and systemd limits give you

cgroups limits let you restrict a service’s CPU, memory, I/O and process count without changing its code: the directives go into the systemd unit and the kernel enforces them. That way one runaway service cannot take resources from the rest. Creating the service itself is covered in the article how to create a systemd service.

DirectiveWhat it limitsValues
CPUQuota=the CPU time ceilingpercent: 20% — no more than 20% of one core’s time, above 100% — time on several cores
CPUWeight=the CPU share under contention1 to 10000, default 100
MemoryHigh=the soft memory thresholdbytes with suffixes K, M, G, T, a percentage or infinity
MemoryMax=the hard memory limitthe same units
MemorySwapMax=swap usage limitbytes, a percentage of swap size or infinity
IOWeight=the block I/O share1 to 10000, default 100
TasksMax=the number of tasks in the unita number, a percentage or infinity

The values come from man systemd.resource-control. Check your systemd version with systemctl --version: the man page describes the latest release.

How to check that you have cgroup v2

There is one check: if the file /sys/fs/cgroup/cgroup.controllers exists, the system uses cgroup v2. According to the Kubernetes documentation and the rootlesscontaine.rs project, v2 is the default in Debian 11 and later, Ubuntu 21.10 and later (22.04 LTS and later is recommended), RHEL 9 and later, and Fedora 31 and later.

CPU: CPUQuota and CPUWeight

CPUQuota= sets a hard ceiling: 20% means the service’s processes will never get more than 20% of one core’s time, and a value above 100% gives time on several cores, for example 200% for two. CPUWeight= sets no ceiling and only matters under contention: a service gets an idle CPU entirely to itself.

CPUWeight= takes values from 1 to 10000, default 100, and divides the CPU among services of one slice in proportion to their weights.

Memory: MemoryHigh, MemoryMax and swap

MemoryMax= is the hard limit: if usage cannot be contained, the OOM killer is invoked inside the unit. MemoryHigh= is the soft threshold: processes are heavily slowed down and memory is taken away from them, but the OOM killer is not invoked. The systemd documentation recommends MemoryHigh= as the main control mechanism and MemoryMax= as the last line of defence.

In practice that means a MemoryHigh= set too low shows up as a slow service, and a MemoryMax= set too low as a killed one. How the OOM killer picks a victim is explained in the article the OOM killer in Linux.

MemorySwapMax= sets an absolute limit on a service’s swap usage: the value 0 forbids it swap entirely. On swap, see the article setting up swap in Linux.

I/O and the number of processes

IOWeight= divides block I/O bandwidth among services of one slice in proportion to the weight, from 1 to 10000, default 100. TasksMax= limits the number of tasks in the unit; the default comes from DefaultTasksMax= in systemd-system.conf. The effect of IOWeight= depends on the device and kernel settings, so verify it by measuring.

How to apply limits: a drop-in step by step

The best way is a drop-in: a small file in the directory /etc/systemd/system/<service>.service.d/ that extends the unit and leaves the original alone. The systemctl edit command creates it for you, and systemctl edit --full opens a full copy of the unit. The values below are examples: tune them to your own service.

  1. Create the file limits.conf in the drop-in directory or run sudo systemctl edit myapp.service.
  2. Put the directives in the [Service] section, as in the example below.
  3. Run sudo systemctl daemon-reload.
  4. Restart the service: sudo systemctl restart myapp.service.
# /etc/systemd/system/myapp.service.d/limits.conf
[Service]
CPUQuota=50%
CPUWeight=50
MemoryAccounting=1
MemoryHigh=512M
MemoryMax=768M
MemorySwapMax=0
IOAccounting=1
IOWeight=50
TasksMax=200

MemoryAccounting=1 and IOAccounting=1 switch accounting on for systemd-cgtop. MemoryHigh= sits below MemoryMax= so that slowing down kicks in first and killing only after it.

How to see the result

systemctl show prints the values in force, and systemd-cgtop shows load by group: it orders cgroups by CPU, memory or disk load. Check right after the restart and again under load. The data is incomplete until MemoryAccounting=1 and IOAccounting=1 are enabled for the services you care about.

sudo systemctl daemon-reload
sudo systemctl restart myapp.service
systemctl show myapp.service -p MemoryHigh -p MemoryMax -p MemorySwapMax -p TasksMax
systemctl show myapp.service | grep -i cpuquota
systemd-cgtop

The quota property name in systemctl show can differ from the directive name, so the example greps for cpuquota. If a service is still slow after the limits, move on to profiling: Linux performance profiling.

Limits for an ordinary user

For an ordinary, non-root user session only the memory and pids controllers are delegated by default; cpu and io have to be delegated separately. This comes from the rootlesscontaine.rs project documentation, not from man systemd, and the default depends on the distribution: look at /lib/systemd/system/user@.service.

# /etc/systemd/system/user@.service.d/delegate.conf
[Service]
Delegate=cpu cpuset io memory pids

After creating the file run systemctl daemon-reload and log in again or reboot the server. The cpuset controller requires systemd 244 or later. System services started by root need no delegation: the directives in the unit are enough.

Frequently asked questions

Is CPUQuota=100% the whole server?

No. 100% is the time of one core. A service with CPUQuota=100% will not take more than one core, and to give it two cores you set 200%.

Where do I start if I do not know how much memory a service needs?

With measuring: enable accounting and watch the service in systemd-cgtop under normal load. Then set MemoryHigh= with headroom above the typical value and MemoryMax= above that.

What should ZevsHost customers do?

On shared hosting the panel manages resource limits, so there is nothing to configure. On a VPS or dedicated server you manage the services: the owner writes the drop-in file with the limits.

Was this article helpful?
← Back to Knowledge Base Ask Support