02 - PagedAttention
本文转载自开源文档站 AI Infra 学习笔记,作者 程治玮(Se7en / cr7258),仅作个人学习存档,内容与配图保持原样。
- 原文链接:https://se7en.mintlify.app/talks/02-pagedattention
- 源仓库:https://github.com/ai-infra-learning/docs
- 许可证:MIT License
- 原始分享:2025-05-25 · 主讲 程治玮
问题讨论
1 引言:为什么大模型推理的内存管理如此关键?
随着大语言模型(LLM)在聊天机器人、代码补全、智能问答等场景中的广泛应用,越来越多的公司开始将其作为核心服务进行部署。但运行这类模型的成本极高。相比传统的关键词搜索请求,处理一次 LLM 推理的代价可能高出十倍以上,而背后的主要成本之一,正是 GPU 内存的使用效率。
在大多数主流 LLM 中,推理过程需要缓存每一步生成过程中的 Key 和 Value 向量(即 KV Cache),以便后续生成阶段引用。这部分缓存并不会随模型权重一起常驻 GPU,而是随着用户请求的长度动态增长和释放。在高并发场景下,不合理的 KV Cache 管理方式会导致大量内存碎片和资源浪费,最终限制可并发处理的请求数量,拉低整体吞吐量。
为了解决这一瓶颈,vLLM 引入了一个全新的注意力机制 —— PagedAttention。它借鉴了操作系统中的虚拟内存分页技术,将 KV Cache 分块存储在非连续的内存地址中,配合 block-level 的共享与 copy-on-write 机制,极大提升了内存利用率,从而显著提高了模型的吞吐能力。
vLLM 团队将 vLLM 的推理吞吐量与 HuggingFace Transformers(HF) 和 HuggingFace Text Generation Inference(TGI) 进行了对比。评估在两种硬件设置下进行:在 NVIDIA A10G GPU 上运行 LLaMA-7B 模型,以及在 NVIDIA A100(40GB)GPU 上运行 LLaMA-13B 模型。实验结果表明,与 HF 相比,vLLM 的吞吐量最高可达 24 倍,与 TGI 相比,吞吐量最高可达 3.5 倍。

本文将结合 PagedAttention 的论文《Efficient Memory Management for Large Language Model Serving with PagedAttention》,深入解析 PagedAttention 的设计理念与实现细节,并说明它是如何有效缓解内存瓶颈,显著提升大模型推理性能的。
2 背景知识:LLM 推理中 KV Cache 的角色
在大语言模型(LLM)如 GPT、OPT、LLaMA 的推理过程中,一个关键机制是自回归生成(autoregressive generation)。这意味着模型会基于用户提供的 prompt(提示词),逐步生成下一个 token,每一步都依赖之前生成的 token。这种生成方式的效率,极大依赖于 Transformer 架构中的自注意力机制(self-attention)。
在 self-attention 中,模型为每个 token 计算三个向量:Query(Q)、Key(K) 和 Value(V)。每生成一个新 token,模型会将当前的 Query 向量与之前所有 token 的 Key 向量进行点积计算注意力分数,再据此对 Value 向量做加权求和。这种计算需要频繁访问此前的 token 信息。

为了避免重复计算这些历史 Key 和 Value 向量,推理系统通常会将它们缓存下来,称为 KV Cache(Key-Value 缓存)。这不仅节省了大量重复计算,也显著提升了推理效率。
推理过程可以划分为两个阶段:
-
prefill 阶段:模型接收完整的用户输入 prompt,并一次性并行计算所有 token 的 Query、Key 和 Value 向量。这一阶段是高度并行的,能够充分利用 GPU 的算力资源,因此属于 compute-bound(计算受限),瓶颈在于算力而非内存。
-
decode 阶段:此阶段模型开始逐个 token 地生成输出。每一步仅处理一个新的 token,模型首先计算其对应的 Query、Key 和 Value 向量。当前 token 的 Query 会与历史及当前的 Key 向量进行点积计算,通过 softmax 得到 attention 权重后,再与历史及当前的 Value 向量进行加权求和,得到当前 token 的 attention 输出。随后,当前步骤产生的 Key 和 Value 向量会被追加写入 KV Cache,以供后续使用。由于该过程是串行的、难以并行加速,且频繁读写缓存数据,因此整体表现为 memory-bound(内存受限),瓶颈主要在 KV Cache 的存储与访问效率。
可以看出,prefill 阶段更侧重于并行计算,而 decode 阶段的性能很大程度上取决于 KV Cache 的内存管理能力。随着生成的 token 数量增加,KV Cache 会线性增长,并逐步占据大量 GPU 显存。
下图展示了一个 13B 参数规模的大语言模型在 NVIDIA A100 40GB 显存 GPU 上推理时的显存使用分布。其中:
- Parameters(26GB, 65%):指模型的权重参数,这部分在加载模型后常驻显存,大小固定;
- KV Cache(>30%):用于存储每个请求的历史 Key 和 Value 向量,随着生成 token 数量动态增长,是最主要的动态内存开销来源;
- Others:主要指推理过程中暂时产生的中间计算结果(如 activation),生命周期短,通常在计算完一层后即被释放,占用较少。

从这张图可以直观看出,KV Cache 是模型推理过程中最主要的“动态”显存负担,它不仅大,而且会随着请求数量和序列长度迅速膨胀。因此,如何高效管理 KV Cache,决定了一个推理系统能否支撑大批量并发请求,是提高吞吐量的关键。
3 内存管理的挑战:KV Cache 为什么成了 LLM 推理的瓶颈?
当前主流的 LLM 推理系统在 KV Cache 的内存管理上普遍存在 3 类结构性问题:显存占用增长快、内存碎片严重,以及缓存难以复用。
3.1 KV Cache 占用迅速增长,极易耗尽显存
以 OPT-13B 为例,论文指出其每个 token 的 KV Cache 占用约为 800KB,计算方式为:
2(Key 和 Value)× 5120(hidden size)× 40(Transformer 层数)× 2 字节(FP16) = 819,200 字节 ≈ 800KB
如果生成完整的 2048 个 token,单个请求的 KV Cache 占用就可达约 1.6GB。在一块 40GB 显存的 A100 GPU 上,这种增长速度意味着仅同时处理少量请求,就可能达到内存瓶颈,直接限制了批处理规模和系统吞吐量。
3.2 预分配导致内存碎片严重
传统推理系统(如 FasterTransformer 和 Orca)通常采用预分配策略:请求开始时,就按最大可能生成的长度(如 2048 token)为每个请求分配一整块连续内存空间。这种方式带来 3 类显著的内存浪费:
- 已预留但尚未使用的空间(Reserved):虽然未来会使用,但当前暂未使用到。
- 内部碎片(Internal Fragmentation):实际 token 数小于预留长度,剩余空间浪费。
- 外部碎片(External Fragmentation):不同请求所需内存大小不一,造成内存块间不连续,产生碎片。

论文中的实验结果显示,再传统系统中真正用于存放 KV Cache 的有效内存占比最低仅约 20.4%,其余全为浪费。
