# Running Memory-Intensive Containers with Apple Container: Best Practices and Configuration

> Discover best practices for running memory-intensive containers with apple/container. Learn to configure RAM, manage builder VMs, and optimize resource usage for peak performance.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: best-practices
- Published: 2026-06-22

---

**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`](https://github.com/apple/container/blob/main/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`](https://github.com/apple/container/blob/main/MemorySize.swift) in [`Sources/ContainerPersistence/MemorySize.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/MemorySize.swift). The parser validates input through `Parser.memoryStringAsMiB` in [`Sources/Services/ContainerAPIService/Client/Parser.swift`](https://github.com/apple/container/blob/main/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`](https://github.com/apple/container/blob/main/ContainerConfiguration.swift) ([`Sources/ContainerResource/Container/ContainerConfiguration.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/ContainerConfiguration.swift)) and passed to the VM runtime.

```bash

# 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:

```bash

# 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`](https://github.com/apple/container/blob/main/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`](https://github.com/apple/container/blob/main/MachineConfig.swift) ([`Sources/ContainerPersistence/MachineConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/MachineConfig.swift)).

To permanently change the default allocation for all future containers:

```bash

# Set machine default to 16 GiB

container machine set memory=16G

```

Details are available in [`docs/container-machine.md`](https://github.com/apple/container/blob/main/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`](https://github.com/apple/container/blob/main/ContainerStats.swift) ([`Sources/ContainerCommands/Container/ContainerStats.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Container/ContainerStats.swift)), the output displays `memoryUsageBytes` versus `memoryLimitBytes`, allowing you to identify when containers approach their limits.

```bash

# 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:

```bash

# Restart the container to free VM memory

container stop my-big-image && container start my-big-image

```

As explained in [`docs/technical-overview.md`](https://github.com/apple/container/blob/main/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 in [`ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/ContainerSystemConfig.swift).
- **Configure the builder separately** using `container builder start --memory` before running large builds.
- **Set machine defaults** with `container machine set memory=` to avoid repeating flags for every command.
- **Monitor with `container stats`** to compare `memoryUsageBytes` against `memoryLimitBytes`.
- **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`](https://github.com/apple/container/blob/main/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`](https://github.com/apple/container/blob/main/MachineConfig.swift). This applies to all future containers and builders, whereas `--memory` flags apply only to individual commands.