LEARN MORE

Memory and sleep

Kiri’s Linux VM takes memory as your containers need it and hands the rest back to macOS while it runs. When nothing has run for a minute, it powers off and holds no memory at all. The next request that needs it boots it again in about 0.15 s, so you rarely notice.

The VM’s limits

The VM boots with a memory ceiling and a number of CPUs. These are the most it may use, not what it takes.

Default Change it
Memory ceiling half the Mac’s RAM, at least 2 GB and at most 8 GB Settings → Resources, from 1 GB up to the Mac’s RAM
CPUs 2 Settings → Resources, from 1 up to the Mac’s CPUs

Settings saves these to ~/.kiri/vm.json and they apply from the VM’s next start. If the VM is running, Settings offers Restart VM to apply, which stops the running containers. The environment variables KIRI_MEMORY_MIB and KIRI_CPUS, set for the daemon, take precedence over Settings.

The CPUs are shared with macOS. The VM only uses them while containers are busy; the daemon itself uses no CPU when idle.

The balloon gives memory back

Inside the ceiling, a memory balloon keeps the VM close to what it actually uses. Every second the daemon asks the agent how much memory the guest holds, counting anonymous, shared and kernel memory but not the page cache, which Linux can drop when asked. It then sets the balloon’s target to that plus 256 MB of headroom, never below 256 MB, and macOS gets the rest.

  • Shrinking is gradual: at most 256 MB per second, so the guest’s caches drain slowly instead of all at once.
  • Growing is immediate. When the guest is short of memory (the kernel reports memory stalls through a PSI trigger), the agent tells the daemon, which grows the target by 1 GB at once, up to the ceiling.
  • Changes under 64 MB are skipped, so the target doesn’t jitter.

The guest kernel also compresses idle pages with zswap, and there is no swap for containers: a --memory limit is a hard limit.

08 GBtimeceiling: the most the VM may takeballoon targetin usepressure: +1 GB at once256 MB steps downcontainers stopVM sleeps60 s idleasleep: 0 MB
An illustration of the balloon's target following what the VM uses: it grows at once under pressure, steps down when containers stop, and falls to zero when the VM sleeps. The shapes are drawn by hand, not measured.

The window’s status bar shows the VM’s memory: what’s in use, and how much the balloon lets it take right now.

Sleeping when idle

The balloon only goes so far: powering the VM off is the one thing that gives all of its memory back to macOS, and a VM that boots in about a tenth of a second can afford to. So the daemon checks every 5 seconds, and puts the VM to sleep once all of these are true for 60 seconds:

  • no container is running,
  • no exec is running,
  • no API request has come in.

The window’s own status checks don’t count as requests, so leaving the window open doesn’t keep the VM awake. A running container does: a docker run -d nginx keeps the VM up until you stop it.

Runningcontainers or requestsIdlenothing for 60 sAsleepVM off, 0 MBRunningagaindocker runboots in ~0.15 sballoon: use + 256 MBstepping downdaemon only, ~15 MBstarts at the ceiling
The VM's life: it stays up while containers run, counts 60 s once they stop, powers off, and boots again on the next request that needs it.

The daemon keeps the container records on the Mac, so docker ps -a still lists everything while the VM is asleep. The menu bar and the window show the VM as Asleep. Stop in the window stops every container and puts the VM to sleep at once.

Builds

BuildKit, which runs in a Kiri container for docker build, would otherwise keep the VM awake for good. When BuildKit containers are the only thing running and no build has run for 5 minutes, the daemon stops them; the next build starts them again.

Changing the timing

Variable Default What it does
KIRI_IDLE_SECS 60 Seconds idle before the VM sleeps. 0 never sleeps.
KIRI_BUILDER_IDLE_SECS 300 Seconds without a build before idle BuildKit containers stop.

These are read by the daemon when it starts, so set them in the daemon’s environment.

What Kiri itself costs

The daemon on the Mac stays at about 15 MB and measured 0.0 % CPU when idle. Measured on one Mac, the daemon’s footprint was 9.0 MB and the agent inside the VM held 0.69 MB. There is no process per container, on the Mac or in the VM. While the VM is awake, Apple’s Virtualization helper process adds about 69 MB on top of what the guest uses. See Benchmarks for every figure.

Limits for one container

Docker’s limit flags set the container’s cgroup in the VM, and docker update changes them while it runs.

Flag What it sets
--memory 512m memory.max, with swap off: a hard limit
--cpus 1.5 cpu.max: 150 ms of CPU time every 100 ms
--cpu-shares 512 cpu.weight, converted from shares as runc does
--pids-limit 100 pids.max

A container can’t use more than the VM has, so a --memory above the ceiling has no extra effect.

© 2026 Kiri · runkiri.com