工具大全
踩坑实录作者:Coocon2026年10月5日4 次阅读约 7 分钟阅读

Ollama 显存不足怎么办:24GB Mac 实测 num_ctx、并发、KV 量化各吃多少内存,以及它不会拦你的那个坑

先回答你搜的问题

  • 先看 ollama ps:PROCESSOR 列显示 100% GPU 就没有「显存不足」;显示 48%/52% CPU/GPU 这类,说明放不下,有一部分在 CPU 上跑。SIZE 列是这个模型实际占的内存。
  • 最常见的原因是上下文开太大:qwen3:4b 在 4k 上下文时占 3.73GB,32k 时占 9.89GB,大头是 KV cache,不是模型本身。
  • 最有效的一招:启动 Ollama 前设 OLLAMA_FLASH_ATTENTION=1 和 OLLAMA_KV_CACHE_TYPE=q8_0(或 q4_0)。实测 32k 上下文从 9.89GB 降到 5.51GB(q8_0)/ 4.31GB(q4_0),生成速度不变。
  • 检查并发数:OLLAMA_NUM_PARALLEL=4 会让内存按 4 倍上下文算,但 ollama ps 的 CONTEXT 列看不出来。不需要并发就设成 1。
  • 别指望 Ollama 拦你:上下文设得远超内存时,它不会报「内存不够」,而是直接开始分配,系统会被拖进疯狂换页。设之前先算一下。
  • Mac 上「挪到 CPU」没那么可怕:实测 qwen3:4b 全部放 CPU 只比全 GPU 慢 25%。

问题背景

本地跑大模型,「显存不足」几乎是绕不过去的一关。在 Mac 上它有两个特殊之处:

  1. Apple Silicon 是统一内存,没有单独的「显存」,但 Ollama 会按 Metal 报告的可用量当显存算;
  2. 你看到的往往不是一句报错,而是变慢、卡顿,或者整台机器开始转风扇、换页。

所以这篇不讲概念,直接在一台 24GB 的 M4 Mac mini 上量:每个设置到底吃多少内存,以及超过之后会发生什么。

问题分析

先看 Ollama 怎么理解这台机器。启动日志原文:

msg="inference compute" library=Metal name=Metal description="Apple M4" total="17.8 GiB" available="17.8 GiB"
msg="vram-based default context" total_vram="17.8 GiB" default_num_ctx=4096

24GB 内存的 Mac,Ollama 认到的显存是 17.8 GiB。按 官方文档,默认上下文按显存分档:小于 24 GiB 给 4k,24~48 GiB 给 32k,48 GiB 及以上给 256k。所以这台机器默认只有 4096。而同一份文档也写着:Tasks which require large context like web search, agents, and coding tools should be set to at least 64000 tokens.

于是大家会去调大上下文,「显存不足」就从这里开始。文档里和内存直接相关的几条:

  • 内存需求按 OLLAMA_NUM_PARALLEL × OLLAMA_CONTEXT_LENGTH 计算(FAQ)
  • KV cache 可以量化:q8_0 约为 f16 的 1/2,q4_0 约为 1/4,前提是开 Flash Attention
  • ollama ps 的 PROCESSOR 列:100% GPU / 100% CPU / 48%/52% CPU/GPU

技术方案与选型

方案 结论 理由
单独起一个 Ollama 实例逐项测 ✅ 采用 在 127.0.0.1:11500 起独立实例,只读复用本机已下载的模型,每测一项就卸载,/api/ps 读占用、/api/generate 读速度
用 27B 模型直接撞内存上限 ❌ 放弃 实验时这台机器上还跑着另一个占 7GB 的回测任务,27B(约 17GB)会把它挤进换页
Docker 里跑 ❌ 排除 官方 FAQ:GPU acceleration is not available for Docker Desktop in macOS,测出来全是 CPU 数据

几项保护措施:

  • 加 OLLAMA_NOPRUNE=1:ollama serve 默认启动时会清理它认为没用的模型文件,实验实例不该动你的模型库;
  • 内存守护脚本:每 2 秒查一次系统可用内存,低于 35% 立即 kill 实验用的 Ollama(后面真触发了一次);
  • 模型用 qwen3:4b(Q4_K_M,模型文件 2.50GB),每次固定生成 128 个 token,temperature 0。

实测过程

1. 上下文长度:大头是 KV cache

默认设置(f16 KV、不开 Flash Attention):

num_ctx ollama ps 占用 PROCESSOR 生成速度
4096(默认) 3.73 GB 100% GPU 35.3 / 35.5 tok/s
8192 4.61 GB 100% GPU 35.5 tok/s
16384 6.37 GB 100% GPU 35.4 tok/s
32768 9.89 GB 100% GPU 33.8 tok/s

模型文件只有 2.50GB,32k 上下文时却占了 9.89GB。粗算下来,qwen3:4b 每多 1k 上下文大约多占 0.21GB(不同模型差别很大,取决于层数和 KV 头数)。

32k 时系统可用内存最低降到 37%,已经接近守护阈值,所以没有继续用 f16 测 64k(按斜率约 16GB)。

2. Flash Attention + KV 量化:同样 32k,占用降一半以上

设置(32k 上下文) 占用 生成速度
默认(f16,不开 FA) 9.89 GB 33.8 tok/s
OLLAMA_FLASH_ATTENTION=1 7.78 GB 36.3 tok/s
FA + OLLAMA_KV_CACHE_TYPE=q8_0 5.51 GB 35.4 tok/s
FA + OLLAMA_KV_CACHE_TYPE=q4_0 4.31 GB 33.6 / 33.5 tok/s
FA + q4_0,64k 上下文 5.77 GB 36.8 / 36.6 tok/s

**开 q4_0 之后,64k 上下文的占用比默认设置下的 32k 还少。**生成速度在 33.5~36.8 tok/s 之间,没有因为量化变慢。服务日志能看到设置生效了:FlashAttention:Enabled KvSize:32768 KvCacheType:q4_0。

质量方面,文档说 q8_0 usually has no noticeable impact,q4_0 在长上下文下的损失 may be more noticeable,并且 GQA 比例高的模型(文档举的例子是 Qwen2)受影响更大。本文只测了内存和速度,没测回答质量,所以建议先用 q8_0。

3. 并发数:看不见的 4 倍

设置 ollama ps 的 CONTEXT 占用
OLLAMA_NUM_PARALLEL=1,num_ctx=8192 8192 4.61 GB
OLLAMA_NUM_PARALLEL=4,num_ctx=8192 8192 9.89 GB

并发 4 路、每路 8k,占用和单路 32k 一字不差(9.89GB),但 ollama ps 的 CONTEXT 列仍然显示 8192。如果你在 Open WebUI、多个编辑器插件之间共用一个 Ollama,又把并发调高了,内存就是这样悄悄翻倍的。

4. 上下文开到远超内存:Ollama 不会拦你

用 num_ctx=262144 请求 qwen3:4b(f16 KV)。原本预期 Ollama 会先估算、发现放不下,然后报错。实际的服务日志:

load request="{Operation:fit … KvSize:262144 … GPULayers:1[ID:0 Layers:1(35..35)] …}"
load request="{Operation:fit … KvSize:262144 … GPULayers:[] …}"
load request="{Operation:alloc … KvSize:262144 … GPULayers:[] …}"
load request="{Operation:alloc … KvSize:262144 … GPULayers:15[ID:0 Layers:15(21..35)] …}"
…
msg="total memory" size="54.6 GiB"

它估算出总共需要 54.6 GiB,比这台机器的 24GB 物理内存多一倍多,但照样进入了分配阶段(Operation:alloc):先试全部放 CPU,再试 15 层放 GPU。16 秒内,系统可用内存从 75% 掉到 23%,守护脚本触发,把实验用的 Ollama kill 掉了。之后服务日志记录 Load failed … error="model failed to load, this may be due to resource limitations or an internal error, check ollama server logs for details"。这句报错是 kill 之后出现的,如果不 kill,它最终会怎样,本文没有测(继续测会拖垮这台机器上的其他服务)。

这就是「显存不足」最危险的形态:不是一句清楚的报错,而是整台机器被拖进换页。设置大上下文之前,先按上面的斜率估一下。

5. 部分挪到 CPU:在 Mac 上没那么慢

用 num_gpu 控制放在 GPU 上的层数(qwen3:4b 共 37 层,4k 上下文):

GPU 层数 ollama ps 显存占比 生成速度
37(全部) 100% 35.4 / 35.5 tok/s
27 60% 30.9 tok/s
18 42% 27.3 tok/s
9 25% 26.3 tok/s
0(全 CPU) 0% 26.6 / 26.3 tok/s

**全部放 CPU 只比全 GPU 慢约 25%。**这和独立显卡的经验不一样:Apple Silicon 的 CPU 和 GPU 共用同一块内存,层放在哪一边都不需要经过 PCIe 在显存和内存之间搬数据(为什么差距只有 25%,本文没有进一步拆解)。所以在 Mac 上看到 CPU/GPU 混合并不意味着「完蛋了」,真正要防的是第 4 节那种总量超过物理内存的情况。(这是 4B 小模型的数据,大模型、长 prompt 的预填充阶段差距可能更大,本文没测。)

实践效果

1. 先诊断:

ollama ps

看 SIZE(实际占用)、PROCESSOR(有没有挪到 CPU)、CONTEXT(单路上下文,注意不含并发倍数)。

2. 大多数情况,加两个环境变量就够了(macOS 上用 launchctl setenv 或在启动 ollama serve 前 export,改完要重启 Ollama):

export OLLAMA_FLASH_ATTENTION=1
export OLLAMA_KV_CACHE_TYPE=q8_0     # 内存特别紧时换 q4_0,代价是长上下文下可能掉质量
export OLLAMA_NUM_PARALLEL=1         # 不需要并发就别开

**3. 上下文按需开,不要一步到顶。**接编程工具确实需要 64k 左右,24GB 的 Mac 上跑 4B 模型,配合 q4_0 实测 5.77GB,完全放得下;7B、14B 就要按比例重新估算。可以用站内的 显存计算器 先算,或者直接看 Mac mini M4 24GB 能跑哪些模型。

4. 设了大上下文之后,留意内存压力(活动监视器的「内存压力」图,或 memory_pressure 命令)。Ollama 不会提前拦你,一旦变红,马上 ollama stop <模型名>。

**5. Mac 用户不必把「挪到 CPU」当成灾难。**小模型全 CPU 也只慢 25% 左右;真正要避免的是总量超过物理内存。

踩坑

  • **以为 Ollama 会先估算再拒绝。**实验设计时把「超大上下文」当成安全的测试项,认为它只会在估算阶段报错。实际上它直接进入了分配阶段,靠内存守护才及时停下。教训:在共享机器上做内存实验,守护脚本必须先于实验启动。
  • **ollama serve 启动时会清理模型文件。**日志里有一行 total unused blobs removed: 0,这次没删东西,但实验实例改用 OLLAMA_NOPRUNE=1 启动,避免误删本机模型库。
  • **prompt 处理速度不能用。**测试提示只有二十来个 token,同样的设置两次跑出 120 和 248 tok/s,这个指标在本文中不引用。

未验证清单:27B 等大模型在 24GB 机器上的分层情况(实验时机器上有其他高内存任务,没有加载);KV 量化对回答质量的影响;超大上下文不被 kill 时 Ollama 最终的结局;长 prompt 预填充阶段 CPU/GPU 的速度差;除 qwen3:4b 以外模型的「每 1k 上下文占用」斜率。除标注两个数值的几组外,其余设置各只跑了 1 次。

相关阅读

这类实测,每周六汇总一封

订阅码农早餐:每天 8:00 一封 AI 编程早报,每周六另附本周 Claude Code / Codex / 本地模型的实测和踩坑汇总。

相关文章

LM Studio 速度慢怎么办:Mac 实测首字等 39 秒的真正原因是 prompt 预填充,不是 GPU 没开满

在 24GB M4 Mac mini 上用 LM Studio 跑 gemma-4-e4b(Q4_K_M)实测:生成速度约 29.5 tok/s,GPU offload 从全开调到全关只慢 11%;真正让人觉得慢的是长 prompt 的预填充——1.3 万 token 的 prompt 要等 39.4 秒才出第一个字(约 330 token/s),全 CPU 时还要再慢 3.4~3.7 倍。相同前缀的第二次请求首字只要 0.1 秒(前缀缓存)。--parallel 4 时同时来 4 个请求,每个只剩 9.7 tok/s。

mac-mini本地大模型+5
pitfalls2026年10月5日7 min
4
llama.cpp 部署 llama-server 还是用 ollama?Mac mini 24GB 同一个 GGUF 实测:ollama 底下跑的就是 llama-server

llama.cpp 部署 llama-server 还是用 ollama?Mac mini 24GB 同一个 GGUF 实测:ollama 底下跑的就是 llama-server

在 24GB Mac mini 上让 llama-server(b11376)和 ollama(0.35.1)加载同一个 GGUF 文件对照:ollama 0.35 的推理进程就是它自带的 llama-server,同参数下速度一样(4B 解码 36.5 vs 36.3 tok/s,27B 都是 6.3)。差别全在默认参数:ollama 默认上下文 4096,官方库模型的超长 prompt 会被静默截到 2050 token,日志里只有一行 WARN;llama-server 默认按显存把上下文开到最大(4B 开到 101120,footprint 14GB 以上),超长时明确返回 400;并发上 llama-server 默认 4 槽并行,ollama 默认排队;ollama 设 32k 加 4 并发会按每路 32k 分配,footprint 约 21GB。文末给出 24GB 机器的推荐启动参数。

qwenmac-mini+6
hands-on2026年10月3日11 min
25

24GB Mac mini 能跑多大的本地大模型?内存账、实测速度与提速方案汇总

一台 24GB 统一内存的 Mac mini 到底能跑什么模型?答案是:27B 的 4-bit 量化就是天花板,且我们真的把 Qwen3.8-27B 在 M4 丐版上完整跑通了——峰值内存 19.4GB,投机解码后 11.7-12.2 tok/s。本文汇总这台机器上的全部实测:各参数量级的内存账、速度预期、三条提速路线的真实效果(DFlash 2 / 原生 MTP / MLX vs llama.cpp),以及量化档位怎么选。

qwendflash+6
ai-tutorials2026年9月4日5 min
600

大模型量化到底损失多少精度?Q8 到 Q2 一张表说清,附 GGUF 怎么选

4-bit 量化会让模型变笨吗?Q3 还能不能用?本文基于 llama.cpp 官方对 Llama-3-8B 全量化档位的 PPL/KLD 实测数据,把 Q8_0 到 IQ1_S 每一档的精度损失讲清楚,给出'内存装得下的前提下选最高档'的具体选择路径,并回答 Q4 与 Q8 差多少、imatrix 有什么用、1.58-bit 是怎么回事等高频问题。

qwenapple-silicon+5
ai-tutorials2026年9月4日7 min
581