Back to Blog

Why Mac 8 GB RAM Feels Like More — Until You Run a Local LLM and Learn What Unified Memory Actually Means

I have used Macs for over a decade and never thought about memory architecture — until Ollama, agents, and Metal forced me to. A technical tour of Apple’s unified memory, CPU/GPU/NPU, PCIe vs on-chip bandwidth, and why the “8 GB feels fine” story has limits.

UMA Unified Memory
400+ GB/s Bandwidth (M-series)
0 PCIe Copy for GPU
NPU Neural Engine

I Ignored This for Ten Years — Local AI Changed That

I have been on Mac daily for well over a decade: Intel MacBook Pros, then M1, then M-series upgrades. Browsers, IDEs, Docker, Kubernetes contexts, Slack, Zoom — the usual platform-engineering load. Memory was something Activity Monitor showed when something felt slow. I never asked why an 8 GB MacBook Air could feel acceptable for light work while an 8 GB Windows laptop often did not.

That changed recently when I started running local LLMs (Ollama, llama.cpp, MLX) and AI agents on my Mac. Suddenly:

  • Activity Monitor showed yellow and red memory pressure with a 7B model loaded
  • swap grew into tens of gigabytes on disk
  • I cared about quantization, context length, and whether the GPU was actually being used

Researching that behaviour led me down Apple’s Unified Memory Architecture (UMA) — and it explained both the decade of “8 GB feels okay” and why local AI is where the illusion breaks. Worth sharing for anyone else who treats RAM as a single number on a spec sheet.

The Traditional PC Mental Model (Why We Expect More RAM)

On a classic discrete-GPU PC or laptop, memory is split:

  • System RAM (DRAM) — attached to the CPU; holds OS, apps, file cache
  • VRAM (GDDR/HBM) — on the graphics card; holds textures, frame buffers, and today model weights for GPU inference

The CPU and GPU talk over PCI Express (PCIe). Even PCIe 4.0 x16 tops out around ~32 GB/s theoretical — real-world less. Every time the GPU needs data that lives in system RAM, or the CPU needs results from VRAM, you pay a copy tax across that narrow link.

Discrete GPU — simplified data path
┌─────────────┐         PCIe (~16–32 GB/s)        ┌─────────────┐
│    CPU      │ ◄──────────────────────────────► │    GPU      │
│  + System   │    copy weights, tensors, KV cache │  + VRAM     │
│    RAM      │         (duplicate storage)          │  (8–24 GB)  │
└─────────────┘                                    └─────────────┘

# Example: 16 GB system RAM + 8 GB VRAM
# LLM needs 10 GB for weights → may not fit in VRAM alone;
# partial offload / CPU fallback / PCIe thrashing

Windows and Linux also run more background services, aggressive caching, and (on many OEM builds) preloaded software. An 8 GB machine there often has 4–5 GB truly free before you open a browser with twenty tabs. The spec says 8 GB; the usable pool is smaller — and the GPU may have almost no dedicated VRAM.

Apple Silicon: Unified Memory Architecture

From M1 onward, Apple put CPU, GPU, Neural Engine (NPU), image signal processor, and other blocks on one System-on-Chip (SoC) with a single pool of physical DRAM — marketed as Unified Memory.

There is no separate “VRAM” chip on the Mac. When Metal or Core ML loads a 4 GB model, those weights sit in the same bytes the kernel uses for your apps. CPU cores, GPU cores, and the NPU access memory through a high-bandwidth on-chip fabric, not through PCIe to a distant card.

Apple Silicon — unified memory (conceptual)
                    ┌──────────────────────────────────┐
                    │         Apple M-series SoC         │
                    │  ┌──────┐ ┌──────┐ ┌────────────┐  │
                    │  │ CPU  │ │ GPU  │ │ NPU (Neural│  │
                    │  │cores │ │cores │ │  Engine)   │  │
                    │  └──┬───┘ └──┬───┘ └─────┬──────┘  │
                    │     └────────┼───────────┘        │
                    │              │ Memory controller   │
                    └──────────────┼─────────────────────┘
                                   │
                          ┌────────▼────────┐
                          │  Unified DRAM   │  ← one pool: "8 GB" is ALL of this
                          │  (on-package)   │
                          └─────────────────┘

Why this makes 8 GB “feel like more”

  1. No VRAM duplication — On a 8 GB Mac, the GPU can use most of that pool for compute when needed. On an 8 GB PC with integrated graphics, a chunk is already reserved; with discrete GPU, weights must fit in separate VRAM or pay PCIe penalty.
  2. Massive memory bandwidth — M1 introduced ~68 GB/s; M2 Pro ~200 GB/s; M3 Max class chips exceed 400 GB/s. LLM inference is often memory-bandwidth bound; Apple’s wide interface helps small models feel snappy.
  3. Zero-copy style sharing — Frameworks like Metal can share buffers between CPU and GPU without copying across PCIe. Same physical pages, different coherency domains — far cheaper than discrete-GPU round trips.
  4. macOS memory management — Compressed memory, aggressive but fast NVMe swap, memory pressure handling, and unified pool accounting make the OS report “8 GB” but stretch it further than many users expect — until pressure goes red.
  5. Efficient cores + tight integration — Apple controls silicon, OS, and GPU drivers (Metal). Less duplicated buffer allocation than a generic PC stack.
💡
“Feels like more” ≠ “is more”

8 GB on Mac is still 8 GB of physical DRAM. UMA changes how efficiently CPU, GPU, and NPU use those bytes — not the capacity ceiling. Local LLMs make that ceiling visible fast.

CPU, GPU, and NPU — Three Compute Engines, One Memory Pool

CPU (Performance + Efficiency cores)

Runs the OS, Ollama’s orchestration, tokenization, Python/Node agent runtimes, and fallback inference when GPU paths are unavailable. On Apple Silicon, P-cores and E-cores share unified memory; the scheduler (and your thermal envelope) decides who gets cycles.

GPU (Metal / unified shader cores)

Local LLM tools use the GPU via Metal (llama.cpp -ngl, Ollama’s backend, MLX on Apple). Matrix multiplications for transformer layers run here. Because weights already live in unified memory, the GPU does not wait for a PCIe copy from “system RAM” — it accesses the same DRAM the loader mapped in.

NPU — Neural Engine (not “NumPy”)

People often typo NPU as “NPy” (NumPy). On Mac, the relevant block is Apple’s Neural Engine — a fixed-function / programmable accelerator for ML ops, exposed through Core ML. It excels at optimised models Apple or vendors compile for ANE; general arbitrary LLM weights (GGUF, custom graphs) usually hit GPU or CPU, not the NPU, unless converted for Core ML.

For agent workflows: the NPU may handle on-device speech, vision, or small classifiers; the 7B chat model in Ollama is predominantly GPU+CPU on unified memory today.

Engine Typical local-AI role Memory access
CPU Agent logic, APIs, small models, fallback inference Unified DRAM, full cache hierarchy
GPU (Metal) LLM inference (7B–13B quantised), embeddings at scale Same unified DRAM — high bandwidth
NPU (Neural Engine) Core ML models — vision, ASR, Apple Intelligence features Same unified DRAM; specialised firmware path

PCIe vs On-Chip Fabric — The Bandwidth Story

This is the technical heart of why Macs feel efficient for mixed workloads:

Link Typical bandwidth (order of magnitude) LLM relevance
PCIe 4.0 x16 (GPU) ~25–32 GB/s theoretical Weight upload, CPU↔GPU tensor copies — bottleneck on discrete setups
PCIe 5.0 x16 ~48–64 GB/s theoretical Better, still far below on-package DRAM bandwidth
Apple unified memory (M1) ~68 GB/s GPU reads weights at memory-controller speed
Apple unified memory (M2 Pro / M3 Pro) ~150–200 GB/s Strong for 7B–13B quantised inference
Apple unified memory (M3 Max / M4 Max) 400+ GB/s Approaches discrete mobile GPU + HBM territory for bandwidth-sensitive ops

Transformer decode is often limited by how fast you can stream weights and KV cache through memory. Apple’s bet: integrate everything and widen DRAM instead of bolting a GPU behind PCIe. For daily apps, that integration is invisible. For LLMs, it is the difference between “runs” and “slideshow.”

RAM vs VRAM — One Number on Mac, Two Budgets on PC

Rough memory budget — 8 GB Mac vs 8 GB + discrete GPU PC
# MacBook Air M2 — 8 GB unified (illustrative)
macOS + WindowServer + apps     ~2–3 GB
Browser (10 tabs)               ~1–2 GB
Available for LLM + GPU         ~3–5 GB  ← GPU uses SAME pool
# 7B Q4_K_M model               ~4.1 GB weights alone → tight / swap

# PC — 8 GB RAM + 6 GB VRAM laptop
System + apps                   ~4 GB RAM used
LLM in VRAM                     up to ~5–6 GB IF framework loads there
If model > VRAM               CPU + PCIe offload → much slower
# "16 GB total" marketing sometimes adds RAM+VRAM — misleading for UMA comparison

Apple’s unified accounting is why Activity Monitor’s “Memory Used” jumps when you load a model — the GPU allocation is not a separate VRAM bar. On Windows Task Manager you see distinct “Dedicated GPU memory” vs system RAM; on Mac it is one pressure gauge.

What I Learned Running Local LLMs and Agents

Practical observations from recent experiments (Ollama, llama.cpp, agent frameworks calling local endpoints):

Where UMA helps

  • 7B quantised models (Q4_K_M, Q5) on 16 GB+ Macs feel genuinely usable — GPU layers saturate unified bandwidth without PCIe stalls.
  • MLX (Apple’s array framework) is designed around unified memory; no CUDA portability tax on Mac.
  • Switching between IDE, browser, and inference — no VRAM “out of memory” when alt-tabbing; instead, unified pressure rises smoothly.

Where 8 GB breaks the story

  • 7B full precision or 13B+ models — weights alone exceed comfortable headroom; macOS swaps aggressively to SSD.
  • Long context windows — KV cache grows with context; 32k+ tokens can consume gigabytes beyond model weights.
  • Multi-agent setups — several processes each holding models or embeddings multiply pressure.
  • Swap latency — Apple NVMe swap is fast, but once you are swap-bound, token generation slows dramatically; fan spins, machine feels “fine” in menu bar but inference is not.
⚠️
Platform engineer’s rule for local AI on Mac

Treat 16 GB as minimum for serious local LLM play; 24–32 GB for 13B+ models, agents, and dev tools concurrently. 8 GB UMA is architecturally elegant — not a magic multiplier for 2026 model sizes.

Commands I actually use to watch this

Inspect memory pressure while inference runs
# Activity Monitor → Memory → Memory Pressure (graph)
# CLI snapshots
vm_stat
memory_pressure
sudo powermetrics --samplers gpu_power -i 1000  # GPU active residency (Apple Silicon)

# Ollama — see what's loaded
ollama ps

# llama.cpp — offload layers to GPU (Metal)
./llama-cli -m model.gguf -ngl 99 -c 4096

macOS Tricks That Stretch 8 GB (And Hide the Architecture)

Part of “feels like more” is software, not just silicon:

  • Memory compression — Inactive pages compressed in RAM before swap
  • Fast unified swap on SSD — Apple NVMe + tight kernel integration; swap is less painful than on HDD-era Macs, but still costs latency for LLMs
  • App Nap / coalesced timers — Background apps yield memory
  • Metal resource heaps — GPU allocations tracked in same pressure model
  • kill -INFO on memory-hungry tabs — Safari and Chrome behave differently; Safari often wins on Mac power and memory

For a decade I benefited from this without naming it. Local AI forced me to read the memory pressure graph like a production SLO dashboard.

Apple Silicon Generations — What Changed for AI

Chip class Unified memory ceiling (config) Bandwidth (approx.) Local LLM sweet spot
M1 / M2 8–24 GB 68–100 GB/s 3B–7B quantised; agents light
M2 Pro / M3 Pro 16–36 GB 150–200 GB/s 7B–13B quantised, moderate context
M3 Max 36–96 GB 400 GB/s 13B–70B quantised, multi-agent
M4 Max 36–128 GB 546 GB/s 70B quantised, large-context agents

Connecting Back to AI Infrastructure Thinking

As someone who spends most days on cloud GPUs, Kubernetes, and production inference, local Mac inference is a useful mental model:

  • Cloud: H100 VRAM is isolated; you pay per GB-hour; networking between nodes is PCIe/NVLink/InfiniBand all over again at datacenter scale.
  • Mac: UMA is the opposite design point — one pool, one bandwidth graph, one pressure metric.
  • Both are bound by memory capacity and bandwidth more often than raw FLOPS for LLM decode.

Running agents locally made me better at cloud sizing conversations: when someone asks for an 8 GB pod for a model, I now ask which 8 GB — and whether weights, KV cache, and runtime fit in one pool without swap.

Conclusion

Mac 8 GB RAM “feels like more” because Apple Silicon unified memory removes the PCIe bottleneck between CPU and GPU, delivers high DRAM bandwidth on-package, and lets macOS compress and swap aggressively — not because Apple violated physics.

I used Macs for ten years without caring. Local LLMs and agents made me care: the same architecture that makes everyday use smooth becomes the constraint when four gigabytes of weights land in the same pool as Chrome and VS Code.

If you are exploring on-device AI: understand UMA, watch memory pressure like a metric, size RAM for the model not the marketing page, and remember — CPU, GPU, and NPU share one ledger. That is the architecture. The rest is quantisation and context length maths.

Building local AI workflows or cloud inference platforms? AI infrastructure post · Consultancy · Contact