先把结论说清楚:一个 8B 模型跑 Q4_K_M,权重 4.68GB,每 1K 上下文的 KV 缓存要 144MB,再加 1GB 左右的运行缓冲,16GB 显存足够;24GB 能装下 32B 稠密模型的 8K 上下文,想上 32K 就得压量化档。下面这套算式我在 M4 16GB 上逐档实测校准过,与本机进程实际内存占用相差不到 5%。
显存由四块组成,只有两块随你变
不管是 Ollama、llama.cpp 还是 vLLM,占用的显存都拆得开:权重、KV 缓存、计算缓冲、框架自身开销。后两块基本是常数,前两块才是你能调的。
写成一行算式:显存 ≈ 权重 + (每 1K 上下文 KV × 上下文长度 / 1024 × 并行槽数) + 计算缓冲 + 框架开销。
权重的数不要猜,直接读 GGUF 文件的真实字节。Qwen3-8B 的 Q4_K_M 是 4.68GB,Q5_K_M 是 5.45GB,Q8_0 是 8.11GB,这三个数来自 Hugging Face 上 unsloth 镜像仓的文件大小,可以自己核。Ollama 拉下来之后本地 blob 文件的字节数也是同一个值。
每 1K 上下文的 KV 用量由一个固定公式给出:2 × 层数 × KV 头数 × 单头维度 × 字节宽度。f16 下每个数值占 2 字节,所以 Qwen3-8B 是 2 × 36 × 8 × 128 × 2 = 147456 字节每 token,折合 144MB 每 1K token。这四个参数用 Ollama 的 show 接口就能读出来,不必翻文档:
curl -s http://127.0.0.1:11434/api/show -d '{"model":"qwen3:8b"}' | python3 -c "
import json,sys
d=json.load(sys.stdin)['model_info']
print('层数', d['qwen3.block_count'])
print('KV头', d['qwen3.attention.head_count_kv'])
print('总头', d['qwen3.attention.head_count'])
print('维度', d['qwen3.embedding_length'] // d['qwen3.attention.head_count'])
"
换成 14B 是 160MB 每 1K,32B 是 256MB,30B-A3B 因为只有 4 个 KV 头反而只要 96MB,70B 是 320MB。这组数会贯穿全文,模型越大、KV 头越多,上下文就越贵。
实测:上下文从 2K 拉到 32K,占用怎么涨
我在一台 M4 16GB 上起了独立的 Ollama 实例,固定并行数为 1、KV 精度 f16,只改 num_ctx,每次请求后读 /api/ps 的 size,同时采样 llama-server 进程的 RSS 做交叉验证。模型是 qwen3:8b,Ollama 版本 0.40.14。
| num_ctx | 并行槽 | KV 精度 | /api/ps 报告 | 进程 RSS | 输出速度 |
|---|---|---|---|---|---|
| 2048 | 1 | f16 | 4.44 GB | — | 19.5 tok/s |
| 4096 | 1 | f16 | 4.73 GB | 5.56 GB | 20.1 tok/s |
| 8192 | 1 | f16 | 5.29 GB | — | 20.4 tok/s |
| 16384 | 1 | f16 | 6.44 GB | 7.25 GB | 20.3 tok/s |
| 32768 | 1 | f16 | 8.77 GB | 9.37 GB | 19.3 tok/s |
| 8192 | 2 | f16 | 6.45 GB | — | 20.6 tok/s |
| 8192 | 4 | f16 | 8.80 GB | — | 20.3 tok/s |
| 16384 | 2 | f16 | 8.77 GB | — | 20.2 tok/s |
| 16384 | 1 | q8_0 | 5.49 GB | — | 19.6 tok/s |
| 32768 | 1 | q8_0 | 6.66 GB | — | 19.9 tok/s |
看斜率比看单点有用。上下文从 2048 涨到 32768,多了 30720 个 token,报告值增加 4.33GB,折合每 1K 上下文 141MB,与公式算出的 144MB 对得上。用 RSS 算的是 145MB 和 132MB,两个口径都在同一个量级。
两个口径相差的部分是固定的,约 0.8GB,属于进程自身和 Metal 分配的差额。所以判断够不够时,用 /api/ps 的数加 1GB 更稳妥。
整张表里输出速度落在 19.3 到 20.6 tok/s 之间,没有明显趋势。这说明 KV 缓存只是提前划走内存,只要没被挤到换出,拉大上下文不拖慢解码。真正拖慢解码的是另一件事,后面踩坑一节会讲。
并行槽是第二个乘数,最常被漏掉
同样 8192 上下文,并行 1 用 5.29GB,并行 2 涨到 6.45GB,并行 4 是 8.80GB。每多一个槽,正好多出一整份 KV,8K 这里是 1.16GB。把权重部分反推出来,基线是 4.13GB,也就是 4.68GB 权重加少量缓冲之后被计入的部分。
验算一下:4.13 + 1.16 × 4 = 8.77GB,跟并行 4 的实测 8.80GB 只差 0.03GB。所以这条算式可以直接用:显存 = 权重 + 单槽 KV × 并行槽数 + 1GB。
这里是绝大多数人算错的地方。大家写显存账时默认并行是 1,实际不是。Ollama 0.40.14 会按可用显存自动定并行数,桌面版尤其容易给你设成 2 或 4。你以为 8B 模型 8K 上下文只要 6GB,实际服务器已经给你开好了 4 个槽,实占 8.8GB。
验证方法很简单,起服务时明确写死并行数,再对比:
OLLAMA_HOST=127.0.0.1:11503 OLLAMA_NUM_PARALLEL=1 OLLAMA_MAX_LOADED_MODELS=1 ollama serve
curl -s http://127.0.0.1:11503/api/ps
这个坑在长上下文场景会放大。假设你想在 8B 上开 32K 上下文、4 个并行槽,按公式是 4.13 + 4.5 × 4 = 22.1GB,24GB 卡直接被吃满,连系统界面都可能掉帧。把并行改成 1,同一份 32K 只要 8.8GB。
KV 存成 q8_0 能省一半,速度几乎不动
Ollama 0.40.14 支持 OLLAMA_KV_CACHE_TYPE,把 KV 从 f16 降到 q8_0。实测 16384 上下文从 6.44GB 降到 5.49GB,省 0.95GB;32768 从 8.77GB 降到 6.66GB,省 2.11GB。上下文越长省得越多,因为省的就是 KV 那一块,斜率从 145MB 每 1K 掉到 73MB。
速度代价可以忽略,16384 下 20.3 变成 19.6,32768 下 19.3 变成 19.9,在噪声范围内。
OLLAMA_KV_CACHE_TYPE=q8_0 ollama serve
环境变量必须在服务启动时给,改完要重载模型才生效,光重启客户端没用。另外这条设置只影响 KV,不影响权重精度,所以它不能替你把 70B 塞进 24GB。
需要说明边界:我只测了占用和速度,没做 q8_0 KV 在长文任务上的质量对比。要在长文档摘要这类任务上依赖它,建议自己用同一段材料跑一遍 f16 与 q8_0 再决定。
按这张表选卡:16GB、24GB、48GB 的上限
权重列来自各模型 GGUF 文件的真实字节,上下文列按上面的公式算出,含 1GB 缓冲。判定时要用可用显存,不是标称显存:Windows 桌面环境系统本身吃掉 1.2 到 1.5GB,Linux 无桌面大约 0.3GB。
| 模型 | 每 1K KV | Q4_K_M | Q5_K_M | Q8_0 | Q4 + 8K | Q4 + 32K |
|---|---|---|---|---|---|---|
| Qwen3-8B | 144 MB | 4.68 GB | 5.45 GB | 8.11 GB | 6.8 GB | 10.2 GB |
| Qwen3-14B | 160 MB | 8.38 GB | 9.79 GB | 14.62 GB | 10.6 GB | 14.4 GB |
| Qwen3-30B-A3B | 96 MB | 17.28 GB | 20.23 GB | 30.25 GB | 19.0 GB | 21.3 GB |
| Qwen3-32B | 256 MB | 18.40 GB | 21.62 GB | 32.43 GB | 21.4 GB | 27.4 GB |
| Llama-3.3-70B | 320 MB | 39.60 GB | 46.52 GB | 69.82 GB | 43.1 GB | 50.6 GB |
16GB 这档,14B 的 Q4_K_M 配 8K 上下文是 10.6GB,跑得开;想上 32K 就是 14.4GB,已经贴到上限,得把并行锁成 1。8B 属于随便玩,Q8_0 加 32K 也才 12.4GB。
24GB 这档,32B 稠密模型的 Q4_K_M 加 8K 是 21.4GB,能装进去但只剩 1GB 余量,任何额外开销都会让它退回 CPU。同一张卡上 30B-A3B 是更聪明的选择,权重 17.28GB、8K 上下文合计 19GB,而且每次只激活约 3B 参数,解码速度接近 8B 稠密模型,长文吞吐比 32B 高出一个档。这类模型的本地实测可以看站内对 40B MoE 只激活 2.5B 的跑分拆解。
48GB 这档才轮到 70B。Q4_K_M 是 39.6GB 权重,加 8K 上下文 43.1GB,能跑但只剩不到 5GB;要 32K 就得 50.6GB,必须上双卡或降到 Q3_K_M 的 31.91GB。
踩坑:四个会让算式失效的地方
第一个坑是权重装得下、长对话才崩。加载一个 8B 模型占 4.4GB,看着很宽裕,你把上下文设成 32K 就多要 4.5GB,再加上并行槽,第一次长输入就 OOM。判断方法是看占用是否随上下文变化:发一个短问题读 /api/ps,再发一个 20K 的长输入读一次,两次差多少就是 KV 实占。差得比公式算的多,说明并行槽不是 1。
第二个坑是并行槽默认值。前面算过,同一份 8K 上下文在 1 槽和 4 槽之间差 3.5GB。做法是启动服务时显式写 OLLAMA_NUM_PARALLEL=1,别指望默认值。
第三个坑是放不进去的代价,在 Mac 和独显上完全不同。我在 M4 上把 num_gpu 从 99 降到 24、12、0,输出速度是 20.4、18.1、16.4、14.9 tok/s,只掉了 27%。统一内存下 CPU 和 GPU 共用一套内存,层落到 CPU 只是算得慢一点。独显不一样,层留在内存里,每算一层都要过 PCIe 搬一次权重,掉的是数量级。我这里没有独显,不给具体倍数,但判断方法一致:看 llama-server 启动日志里 offloaded 的层数,写的是 24/37 就说明有 13 层在 CPU 上。
ps -Ao rss,comm | grep llama-server
第四个坑是上下文买多了用不上。站内此前实测过,16K 以内 Ollama 只把一半上下文当可用输入,4096 实际只能吃 2050 个 token。也就是说你为了保险设成 32768,多付了 4.5GB 显存,拿到的可用输入却远少于账面。这块的细节在 num_ctx 的逐档实测 里写全了,两者要一起算才准。
三个常见问题
24GB 显卡跑 32B 的 Q4_K_M 行不行?
行,但上下文只能给到 8K 左右,权重加 KV 加缓冲是 21.4GB,再涨上下文就会退回 CPU。要 32K 就把量化降到 Q3_K_M(14.87GB),或者换成 30B-A3B 这类 MoE 模型。
显存不够会直接报错吗?
不一定。Mac 上多数情况是明显变慢,你会以为模型不行;独显上可能是硬 OOM 退出。先看 /api/ps 的 size 和启动日志的 offloaded 层数,比看报错快。
只靠量化能把 70B 塞进 24GB 吗?
不能。70B 最小的 Q2_K 也有 24.56GB,加上 8K 上下文的 2.5GB 和缓冲已经超过 27GB。24GB 卡跑 70B 只有一条路,把上下文压到极小并接受大量层在 CPU 上,速度会掉到个位数 tok/s,实用价值很低。
最后给一个可复算的检查顺序:先读 GGUF 字节得权重,再用 2 × 层数 × KV 头 × 维度 × 2 算出每 1K KV,乘以目标上下文和并行槽,加 1GB 缓冲,跟可用显存比。四个数都能自己读出来,算完再决定下载哪个量化档,比先下 20GB 再发现跑不动省事得多。想对比同一张卡上图像模型与文本模型的显存曲线,可以参考 22GB 卡跑 1024 分辨率的实测;并发侧的影响见 NUM_PARALLEL 的四种崩法。
延伸阅读
- Ollama 并发怎么设:NUM_PARALLEL 实测与四种崩法18 小时前
- Strata 0.2.10:8GB显存跑128K上下文5 天前
- 中国电信开源 Xing4.0-29B-A4B:全栈国产,消费级显卡跑 512K 上下文2 月前
- 讯飞星火 X2.6:293B 国产算力训练,4B 端侧 BFCL 拿 71.8 分3 周前
继续读
同一批更新里这几篇值得一看:
- Ollama 上下文怎么设:4096 实测只吃 2050 token2026-11-09
- NVIDIA Dory 1.0 4B 怎么跑:3.7GB GGUF 四档算力实测2026-11-09
- Ollama 并发怎么设:NUM_PARALLEL 实测与四种崩法2026-11-08
想快速查定义?对应的词条在这里:
- Llama词条 · AI 自学笔记
