The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Confirm cgroup v2 | stat -fc %T /sys/fs/cgroup | View examples |
| Show current cgroup | cat /proc/self/cgroup | View examples |
| List available controllers | cat /sys/fs/cgroup/cgroup.controllers | View examples |
| Find unit cgroup | systemctl show api.service -p ControlGroup | View examples |
| Run a limited scope | systemd-run --user --scope -p MemoryHigh=768M -p \
MemoryMax=1G -p CPUQuota=150% make -j4 | View examples |
| Apply memory throttle | MemoryHigh=768M | View examples |
| Apply hard memory limit | MemoryMax=1G | View examples |
| Read memory events | cat \
/sys/fs/cgroup/system.slice/api.service/memory.events | View examples |
| Set relative CPU weight | CPUWeight=200 | View examples |
| Cap CPU bandwidth | CPUQuota=150% | View examples |
| Set relative I/O weight | IOWeight=200 | View examples |
| Limit tasks | TasksMax=512 | View examples |
| List member processes | cat /sys/fs/cgroup/system.slice/api.service/cgroup.procs | View examples |
| Enable child controllers | printf '%s\n' '+cpu +memory +pids' |
sudo tee \
/sys/fs/cgroup/ops.slice/cgroup.subtree_control | View examples |
| Watch cgroup usage | systemd-cgtop --depth=3 | View examples |
| Read CPU pressure | cat /sys/fs/cgroup/system.slice/api.service/cpu.pressure | View examples |
cgroup v2 organizes processes in one hierarchy and applies hierarchical resource policy through controllers. In production, let the system service manager own that hierarchy: express durable limits in units, use transient scopes or services for experiments, and reserve direct cgroupfs writes for delegated subtrees or controlled diagnostics. A limit without monitoring is incomplete—track throttling, pressure, out-of-memory events, and workload latency before and after every change.
Step by step
Detailed examples
Confirm the unified hierarchy and controller availability
A cgroup2fs mount indicates v2 at the conventional path, while /proc/self/cgroup shows the caller's path. cgroup.controllers lists controllers available for distribution at that node; a controller may be absent because of kernel configuration, a boot-time v1 assignment, or an ancestor's policy. Do not infer effective limits from a single file: restrictions compose top-down and a descendant cannot escape an ancestor's ceiling.
stat -fc 'filesystem: %T' /sys/fs/cgroup
cat /proc/self/cgroup
printf 'available: '; cat /sys/fs/cgroup/cgroup.controllers
printf 'enabled for children: '; cat /sys/fs/cgroup/cgroup.subtree_control Use systemd as the production cgroup owner
systemd creates and removes cgroups with unit lifecycle, translates resource properties to the kernel interface, and preserves hierarchy invariants. Put durable settings in a service or slice; use systemd-run for a transient experiment. A user manager can apply only controllers and limits delegated to it, and a transient scope inherits ceilings from its ancestors. Confirm the resulting ControlGroup and effective properties rather than assuming every requested controller was available.
systemd-run --user --scope --unit=build-limited.scope \
-p MemoryHigh=768M \
-p MemoryMax=1G \
-p CPUQuota=150% \
make -j4
systemctl --user show build-limited.scope -p ControlGroup -p MemoryHigh -p MemoryMax -p CPUQuotaPerSecUSec Throttle first, reserve the hard ceiling for containment
memory.high applies reclaim pressure and throttles allocations without invoking the cgroup OOM killer; it is the primary operational control when a monitor can respond. memory.max is a hard containment boundary and may trigger OOM killing when reclaim cannot satisfy it. Leave headroom, load-test realistic working sets, decide whether an entire unit should be treated as one OOM group, and alert on memory.events deltas rather than only current byte usage.
[Service]
MemoryAccounting=yes
MemoryHigh=768M
MemoryMax=1G
MemorySwapMax=256M
OOMPolicy=stop unit_path=/sys/fs/cgroup/system.slice/api.service
cat "$unit_path/memory.current"
cat "$unit_path/memory.peak"
cat "$unit_path/memory.events" Distinguish relative weights from absolute bandwidth ceilings
CPUWeight and IOWeight influence distribution only when sibling cgroups compete for the same resource; they do not reserve capacity. CPUQuota imposes a bandwidth ceiling, where 100% corresponds to one CPU of runtime and values above 100% permit multiple CPUs. I/O controls depend on controller availability, device topology, and scheduler support. Benchmark tail latency and throughput because aggressive CPU quotas or I/O caps can amplify queueing.
[Service]
CPUAccounting=yes
CPUWeight=200
CPUQuota=150%
IOAccounting=yes
IOWeight=200 Bound process creation and monitor rejected forks
The pids controller counts tasks across a cgroup and its descendants. TasksMax maps systemd policy to pids.max and blocks fork or clone with EAGAIN when a new task would violate the limit. Existing membership can temporarily exceed a newly lowered maximum, and moving processes is not a way to test fork behavior. Size the limit for worker bursts, helper processes, and thread-heavy runtimes, then alert on pids.events max increments.
[Service]
TasksAccounting=yes
TasksMax=512 unit_path=/sys/fs/cgroup/system.slice/api.service
cat "$unit_path/pids.current"
cat "$unit_path/pids.max"
cat "$unit_path/pids.events" Respect top-down control and the no-internal-process rule
Controllers are enabled for children through cgroup.subtree_control. A non-root domain cgroup can distribute domain controllers only when it contains no processes itself, keeping workloads in leaves. Moving a PID through cgroup.procs moves all threads of that process, but already charged memory is not migrated with it. Direct writes under /sys/fs/cgroup can conflict with systemd and should occur only inside a formally delegated subtree with ownership, containment, cleanup, and controller boundaries designed in advance.
# CAUTION: privileged cgroupfs writes alter live scheduling and memory policy.
# Use only for a documented subtree that the system manager delegated to ops.slice.
cat /sys/fs/cgroup/ops.slice/cgroup.controllers
printf '%s\n' '+cpu +memory +pids' | sudo tee /sys/fs/cgroup/ops.slice/cgroup.subtree_control
cat /sys/fs/cgroup/ops.slice/cgroup.subtree_control Correlate counters, pressure, throttling, and application latency
systemd-cgtop provides a live hierarchy view when accounting is available. cpu.stat exposes usage and throttling, memory.events reports pressure and OOM outcomes, and PSI files quantify time stalled on CPU, memory, or I/O. Counters are cumulative and some events are hierarchical, so monitoring should store rates, distinguish local from descendant events where local files exist, and correlate every policy adjustment with service-level indicators.
unit_path=/sys/fs/cgroup/system.slice/api.service
systemctl show api.service -p ControlGroup -p MemoryCurrent -p MemoryPeak -p TasksCurrent
cat "$unit_path/cpu.stat"
cat "$unit_path/cpu.pressure"
cat "$unit_path/memory.events"
cat "$unit_path/io.pressure" Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



