Running Memory-Intensive Containers with Apple Container: Best Practices and Configuration
Use the --memory flag to allocate sufficient RAM to the Linux VM, configure the builder VM separately with container builder start --memory, and restart containers periodically to reclaim host memory since the macOS Virtualization framework does not support full memory ballooning.
Apple Container (apple/container) runs each container inside a lightweight Linux VM created by the macOS Virtualization framework. Unlike traditional container runtimes that allocate memory directly to processes, memory is reserved at the VM level, which requires specific configuration strategies for memory-intensive workloads.
Understanding the VM-Based Memory Architecture
Containers in apple/container execute within isolated Linux VMs rather than directly on the host kernel. According to the source code in Sources/ContainerPersistence/ContainerSystemConfig.swift, the default VM allocation is 1 GiB of RAM and 4 CPUs for both containers and the builder. This architecture provides strong isolation but introduces unique constraints: memory allocated to a VM remains claimed by that VM until it stops, regardless of whether the container processes inside have freed that memory.
Allocating Memory for Individual Containers
To run memory-intensive applications, you must explicitly override the default 1 GiB limit using the --memory (or -m) flag on every container run, container build, or container builder start command.
The flag accepts size suffixes (K, M, G, T, P) parsed by MemorySize.swift in Sources/ContainerPersistence/MemorySize.swift. The parser validates input through Parser.memoryStringAsMiB in Sources/Services/ContainerAPIService/Client/Parser.swift, which enforces a minimum allocation of 200 MiB and ensures the value fits into a 64-bit integer. The final value is stored in memoryInBytes within ContainerConfiguration.swift (Sources/ContainerResource/Container/ContainerConfiguration.swift) and passed to the VM runtime.
# Run a container with 12 GiB of RAM
container run --rm --cpus 8 --memory 12g my-big-image
Configuring the Builder VM
The build environment runs in its own separate VM that also defaults to 1 GiB. For memory-intensive builds, increase the builder resources before starting the build process:
# Start the builder with 32 GiB of RAM
container builder start --cpus 8 --memory 32g
container build -t heavy-app .
As documented in docs/how-to.md, the builder VM persists until explicitly stopped, so resource changes require restarting the builder.
Adjusting Default Machine Configuration
Rather than specifying memory per command, you can modify the underlying machine configuration that applies to all containers. The default machine uses "half of host memory" as specified in MachineConfig.swift (Sources/ContainerPersistence/MachineConfig.swift).
To permanently change the default allocation for all future containers:
# Set machine default to 16 GiB
container machine set memory=16G
Details are available in docs/container-machine.md. This setting affects the underlying VM infrastructure rather than individual container instances.
Monitoring Memory Usage
Track real-time consumption using container stats or container top to ensure your allocations match actual usage. According to ContainerStats.swift (Sources/ContainerCommands/Container/ContainerStats.swift), the output displays memoryUsageBytes versus memoryLimitBytes, allowing you to identify when containers approach their limits.
# Monitor live memory statistics
container stats my-big-image
Managing Memory Reclamation
Due to limitations in the macOS Virtualization framework, full memory ballooning is not supported. Pages freed inside the VM remain allocated to the VM from the host perspective until the VM stops. Consequently, long-running memory-intensive containers can cause the host to appear to leak RAM.
To reclaim memory on the host system:
# Restart the container to free VM memory
container stop my-big-image && container start my-big-image
As explained in docs/technical-overview.md, periodic restarts are the only method to return freed memory to macOS until ballooning support is implemented.
Summary
- Always specify
--memory(e.g.,--memory 12g) when starting containers or builders to override the 1 GiB default defined inContainerSystemConfig.swift. - Configure the builder separately using
container builder start --memorybefore running large builds. - Set machine defaults with
container machine set memory=to avoid repeating flags for every command. - Monitor with
container statsto comparememoryUsageBytesagainstmemoryLimitBytes. - Restart containers periodically to reclaim host memory, as the Virtualization framework lacks ballooning support.
Frequently Asked Questions
What is the minimum memory allocation for containers?
The minimum memory allocation is 200 MiB. This is enforced by Parser.memoryStringAsMiB in Sources/Services/ContainerAPIService/Client/Parser.swift, which validates all user-provided memory strings and rejects values below this threshold.
Why doesn't memory return to macOS after my container frees it inside the VM?
The macOS Virtualization framework does not currently support full memory ballooning. Once memory is allocated to the Linux VM, it remains assigned to that VM until it stops, regardless of whether the container processes have freed those pages. Restarting the container is required to return memory to the host.
Should I configure memory for the builder or the container?
Configure both. The builder VM (set via container builder start --memory) handles compilation and image building, while container runtime memory (set via container run --memory) handles execution. They operate in separate VMs with independent memory pools, so each requires explicit configuration for memory-intensive tasks.
How do I make memory settings persistent across all container commands?
Use container machine set memory=<size> to change the default machine configuration stored in MachineConfig.swift. This applies to all future containers and builders, whereas --memory flags apply only to individual commands.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →