Where the Mac's wall actually is
The napkin math from foundations.lesson4 tells you roughly how much memory a model needs. The reality is that macOS doesn't let your GPU lock 100% of unified memory — there's a wired-memory ceiling that varies by Mac SKU, typically reserving ~25% of total RAM for OS use and other apps. On a 512 GB M3 Ultra Studio, the practical GPU ceiling is closer to 380 GB; on a 64 GB MacBook Pro, closer to 48 GB.
This lesson is the diagnostic toolkit for figuring out where your wall is and what to do when you hit it.
The diagnostic commands
Three sysctl values tell you everything you need to know about the wired-memory situation:
hw.memsize— total physical unified memory in bytes.iogpu.wired_limit_mb— explicit GPU wired-memory cap in MB.0means "system default" (typically ~75% of total).vm.memory_pressure(viamemory_pressuretool) — current pressure state (normal, warn, critical).
Raising the ceiling — when it's safe
You can raise iogpu.wired_limit_mb via sudo sysctl iogpu.wired_limit_mb=N to give the GPU more memory than the default. Whether this is safe depends on what else you're running:
- Mac Studio with 192-512 GB dedicated to ML work, no other heavy apps — raising to 90% of total is reasonable.
- MacBook with 16-64 GB running an editor, browser, and other apps — DON'T raise it. macOS will start swapping or killing processes if the OS doesn't get its share.
- If you raise it temporarily for one large job, set it back when done — the value persists across the session but resets at reboot.
What to do when you hit the wall
- Drop quantization — Q4 → Q4 with smaller group_size, or Q4 → mixed_3_4 (Track 3). Each step shaves real memory.
- Shorten context — KV cache scales linearly with sequence length. If you're seeing OOM during long-context generation, cap
max_tokensor use a smaller-context model. - Shrink the model — drop one tier (70B → 13B) before fighting OS-level memory limits. Cheaper than raising sysctl.
- Use a smaller base model + LoRA instead of a larger model in full precision. Track 4's lessons apply here too.
The peak-memory measurement workflow
Whenever you commit a model + workload to production, measure peak memory once. mx.get_peak_memory() at the end of a representative inference run gives you the actual ceiling. Add 20% safety margin, ensure that's still under your wired-memory cap, and you're calibrated.