# Memory Ballooning Limitations in Apple Container: How to Manage Container Memory

> Discover memory ballooning limitations in Apple container and learn effective memory management strategies for your containers to prevent host resource exhaustion.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: deep-dive
- Published: 2026-06-13

---

**Apple's `container` runtime executes each container in a lightweight VM with partial memory ballooning support, requiring manual memory management through explicit limits, periodic restarts, and active monitoring to prevent host resource exhaustion.**

The `apple/container` repository provides a macOS-native container runtime built on the Virtualization framework. Because each container runs inside its own virtual machine, understanding **memory ballooning limitations** is essential for maintaining system stability. Unlike Linux-based container engines, this architecture prevents automatic memory reclamation, forcing you to adopt specific strategies to manage container memory effectively.

## Understanding Memory Ballooning Limitations

The macOS Virtualization framework provides only partial support for memory ballooning, preventing the dynamic return of freed memory from guest VMs to the host. This limitation affects how `container` handles memory allocation and deallocation for every containerized workload.

### No Automatic Reclamation of Freed Pages

When the guest Linux OS releases memory pages, they are **not** returned to the macOS host. According to [`docs/technical-overview.md`](https://github.com/apple/container/blob/main/docs/technical-overview.md), the Virtualization framework cannot reclaim these freed pages, meaning the VM retains all allocated memory until the container stops. This behavior differs fundamentally from traditional Linux containers where the kernel immediately reclaims unused memory.

### Static Allocation Behavior

While the VM allocates only the amount of RAM that the containerized process actually uses, the upper limit you specify (e.g., `--memory 16g`) acts as a static ceiling. The implementation in [`Sources/ContainerResource/Container/ContainerConfiguration.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/ContainerConfiguration.swift) defines the default memory setting as `1024.mib()` (1 GiB), and this allocation never dynamically decreases during the container's lifecycle regardless of actual usage.

### Memory Bloat Risks

Running multiple memory-intensive containers causes the host's RAM usage to grow continuously because each VM retains its maximum allocated pages. Without intervention, this can lead to system-wide performance degradation or out-of-memory conditions on the Mac host, as each container VM holds onto memory it no longer actively needs.

## How to Manage Container Memory Effectively

Given these constraints, you must implement manual memory management strategies to prevent resource exhaustion while allowing containers to function properly.

### Set Explicit Memory Limits

Always specify memory constraints when creating containers using the `-m` or `--memory` flag. The parser in [`Sources/Services/ContainerAPIService/Client/Parser.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/Parser.swift) converts these human-readable strings (like `4g` or `512m`) into byte values for the VM configuration. Without explicit limits, containers default to 1 GiB allocations that may be insufficient or excessive for your workload.

### Monitor Resource Usage

Track `memoryUsageBytes` and `memoryLimitBytes` using the `container stats` command, or observe host-level consumption via Activity Monitor. Regular monitoring helps identify containers approaching their limits or consuming excess memory due to the ballooning limitations, allowing you to intervene before the host exhausts available RAM.

### Restart Containers to Free Memory

Since freed pages are not automatically returned to the host, periodically restart containers that have grown large. Stopping and starting a container discards the VM's allocated pages and resets memory usage to the configured limit, immediately freeing resources on the macOS host.

### Adjust Limits for Existing Containers

Update memory allocations for existing containers using the `container set` command. Changes take effect on the next container start, allowing you to scale resources up or down based on observed workload requirements without rebuilding the container image.

## Code Examples for Memory Management

### Run a Container with Memory Limits

```bash
container run -d --name web \
  --memory 4g \
  nginx:latest

```

The VM allocates at most 4 GiB for this container, parsing the limit through [`Parser.swift`](https://github.com/apple/container/blob/main/Parser.swift) and storing it in the container configuration.

### Build Images with Builder Container Limits

```bash
container builder start \
  --cpus 8 \
  --memory 16g

```

The builder VM receives an 8-CPU, 16-GiB allocation, preventing build processes from consuming excessive host memory during compilation.

### Inspect Running Container Memory Usage

```bash
container stats web

```

This displays `memoryUsageBytes` and `memoryLimitBytes` reported by the VM, helping you identify containers requiring restart or limit adjustment.

### Restart to Release Retained Memory

```bash
container stop web
container start web

```

After restart, the VM discards any previously allocated pages, freeing host RAM that could not be reclaimed through ballooning.

### Update Memory Limits for Existing Containers

```bash
container set --name web memory=8g

```

This updates the VM's configured limit in [`ContainerConfiguration.swift`](https://github.com/apple/container/blob/main/ContainerConfiguration.swift); the change takes effect on the next container start.

## Key Implementation Files

Understanding these source files clarifies how `container` handles memory allocation under the Virtualization framework:

- **[`docs/technical-overview.md`](https://github.com/apple/container/blob/main/docs/technical-overview.md)** — Describes the partial ballooning support and the necessity of container restarts to reclaim memory.
- **[`docs/how-to.md`](https://github.com/apple/container/blob/main/docs/how-to.md)** — Documents practical usage of `--memory` and `--cpus` flags when running containers.
- **[`docs/command-reference.md`](https://github.com/apple/container/blob/main/docs/command-reference.md)** — Lists the `-m, --memory` flag specifications and granularity requirements.
- **[`Sources/Services/ContainerAPIService/Client/Parser.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/Parser.swift)** — Parses memory strings (e.g., `4g`, `512m`) into byte values for VM configuration.
- **[`Sources/ContainerResource/Container/ContainerConfiguration.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/ContainerConfiguration.swift)** — Stores the default memory setting (`1024.mib()`) and VM resource allocation logic.

## Summary

- Apple's `container` runs workloads in lightweight VMs with **partial memory ballooning support** that prevents automatic reclamation of freed pages.
- Memory limits are **static** and default to 1 GiB unless overridden with the `--memory` flag during container creation.
- **Periodic restarts** are required to free memory back to the host, as the Virtualization framework cannot reclaim pages released by the guest Linux OS.
- Use **`container stats`** for monitoring and **`container set`** to adjust limits for existing containers, with changes applying on the next start.
- Consult [`docs/technical-overview.md`](https://github.com/apple/container/blob/main/docs/technical-overview.md) and [`ContainerConfiguration.swift`](https://github.com/apple/container/blob/main/ContainerConfiguration.swift) for detailed implementation specifics.

## Frequently Asked Questions

### Why doesn't `container` automatically return freed memory to the host?

The macOS Virtualization framework provides only partial ballooning support. As documented in [`docs/technical-overview.md`](https://github.com/apple/container/blob/main/docs/technical-overview.md), the guest Linux OS cannot return released pages to the macOS host, causing the VM to retain allocated memory until the container restarts. This architectural limitation requires manual intervention to free resources.

### What is the default memory limit for new containers?

According to [`Sources/ContainerResource/Container/ContainerConfiguration.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/ContainerConfiguration.swift), the default memory allocation is `1024.mib()` (1 GiB). You can override this default using the `--memory` flag when running containers or starting the builder, as parsed by [`Sources/Services/ContainerAPIService/Client/Parser.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/Parser.swift).

### How do I free up memory used by a running container?

You must stop and restart the container. Because of the memory ballooning limitations, simply freeing memory inside the container does not return it to the host. Running `container stop` followed by `container start` discards the VM's allocated pages and resets memory usage to the configured limit.

### Can I change the memory limit of a running container?

No, you cannot change limits on a running container. Use `container set --name <name> memory=<value>` to update the configuration, then restart the container for the new limit to take effect. The change updates the VM's configuration file, but the Virtualization framework requires a restart to apply new memory constraints.