显存
本文用于整理 GPU 显存的基础概念和 LLM 推理中的显存组成。
1. 显存是什么
显存是 GPU 上用于存放计算数据的高速存储空间。和 CPU 使用的系统内存不同,显存直接服务于 GPU 核心计算,模型权重、输入张量、中间结果、KV Cache、运行时缓冲区都会放在这里。
对 LLM 部署来说,显存通常决定两件事:
- 模型能不能加载。
- 在指定上下文长度和并发下能不能稳定生成。
很多时候,“显卡有 24GB 显存”并不等于“可以跑 24GB 的模型权重”。推理框架、CUDA runtime、KV Cache、workspace 和碎片都需要额外空间。
2. VRAM、HBM 和 GDDR
VRAM 是显存的泛称,HBM 和 GDDR 是常见显存技术路线。
| 类型 | 常见位置 | 特点 | 典型场景 |
|---|---|---|---|
| GDDR | 消费级 GPU、工作站卡、部分推理卡 | 成本相对低,容量和带宽适中 | 本地开发、视觉任务、中小模型推理 |
| HBM | 数据中心训练卡和高端推理卡 | 带宽高、能效好、封装复杂、成本高 | 大模型训练、高并发推理、长上下文服务 |
| 片上 SRAM / Cache | GPU 芯片内部 | 速度极快但容量小 | 算子内部数据复用,用户通常不直接管理 |
选型时不要只看显存容量。对于大模型推理,显存带宽同样关键,因为每生成一个 token 都会大量读取模型权重和 KV Cache。
3. 容量和带宽
显存容量回答“放不放得下”,显存带宽回答“读取得快不快”。
| 指标 | 含义 | 对 LLM 的影响 |
|---|---|---|
| 显存容量 | 单卡可用的显存大小 | 决定模型权重、KV Cache、运行时开销和并发上限 |
| 显存带宽 | GPU 读写显存的速度 | 影响 decode 阶段吞吐,尤其是小 batch 或访存瓶颈明显时 |
| 显存类型 | GDDR、HBM 等 | 间接影响带宽、能效、成本和硬件形态 |
简单判断:
- 显存容量不足,会直接 OOM,模型无法加载或请求无法继续。
- 显存带宽不足,模型能跑,但 token 生成速度和吞吐可能上不去。
- 高算力但低带宽的卡,不一定适合大模型推理。
4. LLM 推理中的显存组成
推理时可以先用这个粗略公式理解:
总显存 ≈ 权重显存 + KV Cache 显存 + 激活/临时张量 + workspace/runtime 开销 + 冗余空间
4.1 权重显存
权重显存是模型参数本身占用的空间,主要由参数量和精度决定:
权重显存 ≈ 参数量 × 每个参数占用字节数
| 精度 | 字节/参数 | 说明 |
|---|---|---|
| FP32 | 4 | 训练或特殊场景较多,推理较少使用 |
| FP16 / BF16 | 2 | 常见推理精度 |
| FP8 / INT8 | 1 | 依赖硬件、框架和量化方案 |
| INT4 / 4-bit | 0.5 | 本地部署和低显存推理常见,但效果和速度要实测 |
例如 7B 模型使用 FP16 推理,仅权重大约就是:
7B × 2 bytes ≈ 14 GB
这还没有算 KV Cache 和框架开销。
4.2 KV Cache 显存
KV Cache 保存已经处理过的 token 的 Key / Value,用于避免每次生成都重新计算完整上下文。它能提升生成效率,但会随着上下文长度和并发增长。
影响 KV Cache 的主要因素:
- 模型层数。
- KV head 数和 head dim。
- 上下文 token 数。
- 并发请求数。
- KV Cache 精度。
- 是否使用 MHA、GQA 或 MQA。
简化理解:
KV Cache 显存 ∝ 层数 × KV 维度 × token 数 × 并发数
长上下文服务中,KV Cache 可能比权重更快成为瓶颈。尤其是多个用户同时保留长对话时,即使模型权重已经量化,显存仍然可能被 KV Cache 占满。
4.3 激活、workspace 和 runtime 开销
除了权重和 KV Cache,推理还会产生一些额外显存占用:
| 项目 | 说明 |
|---|---|
| activation / 临时张量 | 算子执行时产生的中间结果 |
| CUDA workspace | cuBLAS、cuDNN、FlashAttention 等 kernel 需要的临时缓冲 |
| runtime 开销 | CUDA context、NCCL、推理框架内存池、图优化缓存等 |
| 通信缓冲 | 张量并行、流水线并行、多卡通信时使用 |
| 内存池预留 | vLLM、TensorRT-LLM、SGLang 等框架可能会预留一部分显存 |
生产部署中通常要预留 10% 到 30% 的冗余空间。长上下文、高并发、多卡并行或动态 batch 场景,预留空间应更保守。
5. 显存碎片
显存碎片指总空闲显存看起来够,但连续可分配空间不够,导致新的大块显存申请失败。
常见诱因:
- 请求长度差异很大,KV Cache 频繁申请和释放。
- batch 大小和序列长度动态变化。
- 多个进程共享同一张 GPU。
- 框架内存池配置不合理。
- 服务长时间运行后没有释放某些缓存。
表现通常是:nvidia-smi 看到还有剩余显存,但程序仍然报 OOM。推理框架的 PagedAttention、block manager、预分配内存池等设计,就是为了解决长上下文和并发下的碎片问题。
6. 显存利用率怎么看
显存占用高不一定是坏事。推理框架为了减少动态分配开销,可能会主动预留大块显存。
需要区分三个概念:
| 指标 | 含义 | 判断方式 |
|---|---|---|
| 已占用显存 | 进程已经申请或预留的显存 | nvidia-smi、nvitop |
| 实际有效负载 | 权重、KV Cache、请求数据等真正用于服务的部分 | 推理框架指标、日志、profiling |
| 显存余量 | 还能承受更长上下文、更高并发或突发请求的空间 | 压测和 OOM 边界测试 |
生产环境不建议把显存长期压到极限。即使平均占用正常,p95 / p99 请求长度、突发并发、热更新和模型切换都可能触发 OOM。
7. OOM 常见原因
| 原因 | 现象 | 处理方向 |
|---|---|---|
| 权重太大 | 模型加载阶段 OOM | 换更大显存、多卡切分、量化、换小模型 |
| 上下文太长 | 长输入或长对话时 OOM | 限制 max context、裁剪历史、摘要、RAG 分块 |
| 并发太高 | 压测或流量高峰 OOM | 限流、降低 batch、减少并发、增加实例 |
| KV Cache 占用过高 | decode 阶段显存持续增长 | 使用 GQA/MQA 模型、KV Cache 量化、PagedAttention |
| 多进程抢显存 | 单进程能跑,多服务共存后 OOM | 固定 GPU 绑定、隔离实例、限制每进程显存 |
| 运行时碎片 | 有剩余显存但仍 OOM | 重启服务、调整内存池、减少动态 shape 波动 |
| 框架预留过多 | 启动后显存被一次性占满 | 调整 gpu_memory_utilization 等参数 |
8. 显存优化方式
可以按优先级从低风险到高改动排查:
- 降低最大上下文长度。
- 降低并发数或 batch 上限。
- 使用更小模型。
- 使用 FP16 / BF16 而不是 FP32。
- 使用 INT8、INT4、AWQ、GPTQ、GGUF 等量化方案。
- 选择使用 GQA / MQA 的模型,降低 KV Cache。
- 使用支持 PagedAttention 或更好内存管理的推理框架。
- 启用 KV Cache 量化或 FP8 KV Cache。
- 使用 tensor parallel、pipeline parallel 或多实例部署。
- 使用 CPU offload,但要注意 PCIe 传输会带来延迟。
不要只看“模型能不能加载”。真正上线前,还要用目标输入长度、目标并发和真实输出长度压测显存边界。
9. 快速判断清单
遇到显存问题时,可以按下面顺序判断:
- 模型权重是否已经接近单卡显存上限。
- 当前精度是 FP32、FP16 / BF16、INT8 还是 INT4。
max_model_len、最大输入长度和最大输出长度是多少。- 同时在线的请求数和保留会话数是多少。
- 推理框架是否预留显存,预留比例是多少。
- 是否有其他进程占用同一张卡。
- OOM 发生在加载阶段、prefill 阶段还是 decode 阶段。
- 是否启用了多卡并行、CPU offload 或 KV Cache 优化。
一句话总结:显存不是只装模型权重的空间,而是模型权重、KV Cache、运行时开销和并发余量共同竞争的资源。