一句话定义
显存碎片(Memory Fragmentation)指显卡显存总量还有富余,但空闲部分被切成一堆互不相邻的小块,凑不出一块足够大的连续空间,于是分配失败、程序报出 OOM。
打个比方
一个能停 100 辆车的停车场只剩 20 个空位,却散落在各个角落。你要停的是一辆需要连续 20 个车位的大巴——空位总数够了,车还是进不去。显存分配同理:很多操作要的是一整段连续地址,不是“总量够就行”。
两种浪费要分清:外部碎片是空闲空间零散、拼不成连续块;内部碎片是空间已经分出去了但没用满——比如按最大长度预留 10000 token 的位置,实际只用了 2000。
为什么大模型推理特别容易碎
推理时每个请求的 KV cache(键值缓存)随对话变长而增长、结束时释放。传统做法是按“最大可能长度”给每个请求预留一整块连续显存。请求一多,预留、释放反复发生,显存就像被反复剪裁的纸,留下形状各异的小洞。这时来个长请求,它要的连续块比任何单个空洞都大,于是报 OOM——而 nvidia-smi 显示空闲显存还有好几个 GB。典型症状是:同样流量,重启服务又能跑一阵,因为重启换来了一整块干净的连续显存。
它和 PagedAttention 的因果关系
这个痛点直接催生了 AI 词典:PagedAttention">PagedAttention(分页注意力)。它借用操作系统的虚拟内存分页(paging)思想:把 KV cache 切成固定大小的块(block),块与块不必连续,再用一张 block table 记录“逻辑第几块 → 物理在哪里”。请求用多少分配多少,释放时按块归还。连续性的硬要求被取消,外部碎片基本消失,内部碎片被压到“每个请求最后一块用不满”的量级。顺序上很清楚:先有碎片这个坑,才有 PagedAttention 这种填法;代价是引入了一层间接寻址。
(各框架实现细节与收益口径不同,以官方页面为准。)
别和这几件事混了
| 现象 | 空闲显存趋势 | 能否拿到大块 | 常见原因 |
|---|---|---|---|
| 真的不够 | 一直很少 | 不能 | 模型或批量本身超了 |
| 显存泄漏 | 只降不升 | 不能 | 有缓存/张量没释放 |
| 外部碎片 | 够但零散 | 不能 | 空闲块不连续 |
| 内部碎片 | 够 | 能,但浪费 | 按最大长度预留 |
对从业者意味着什么
看到 OOM,先别急着砍 batch size 或换小模型,先分清是“真不够”还是“碎得放不下”。实际动作:算清一次分配真正需要的连续块有多大;推理框架尽量选支持分页式 KV 管理的(vLLM、SGLang、TensorRT-LLM 等都有类似思路,支持范围以各自官方文档为准);训练侧留意 PyTorch 缓存分配器的块拆分策略——它同样会留下碎片。
