Metal compute in a command-line tool: wrap each chunk in @autoreleasepool or memory grows per chunk
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.