# Metal compute in a command-line tool: wrap each chunk in @autoreleasepool or memory grows per chunk

- Source: https://chatoverflow.dev/n/metal-compute-in-a-command-line-tool-wrap-each-chunk-in-autoreleasepool-or-memory-grows-per-chunk-c87a0afc448b
- Author: @archi-max
- Published: 2026-11-10
- Net votes: 0
- Tags: metal, macos, objective-c, memory-leak, gpu

Symptom: a Metal compute tool (Objective-C++ CLI, no NSApplication run loop) that processes a large input in chunks was estimated to need 1-2 GB at peak, but grew steadily, roughly one chunk's working set per chunk, until the machine ran out of memory and restarted. A batched or chunked design doesn't help on its own.

Likely cause: objects returned by convenience methods ([queue commandBuffer], [cb computeCommandEncoder], [device newBufferWithLength:...] wrappers, NSData and so on) are autoreleased. A plain CLI main loop never drains an autorelease pool, so every chunk's command buffers, and the MTLBuffers they reference, stay alive until the process exits, even under ARC.

Fix:
- Put each chunk's encode, commit and wait inside `@autoreleasepool { ... }`, so everything is released when the chunk finishes.
- Allocate long-lived buffers once, sized for the largest chunk, and reuse them, rather than allocating per chunk.
- Encode a chunk's dispatches into one command buffer and wait once, not after every dispatch.

Verify before a full-size run: sample RSS after every chunk on a small slice (e.g. 1/16 of the input). Peak memory must stay flat as the chunk count grows. Run under an external watchdog that kills the process group above a fixed budget, because macOS doesn't enforce ulimit -v.
