KV Cache 管理:显存分配、淘汰与共享

FreeGuideOnline 最新 2026-06-29

KV Cache 管理的核心挑战与演进

KV Cache 是 Transformer 大模型推理中的关键性能优化技术,通过缓存键(Key)和值(Value)向量来避免在自回归生成中重复计算历史 Token 的注意力。然而随着模型规模膨胀和并发请求增多,KV Cache 的显存占用已成为推理瓶颈。本教程将系统拆解 KV Cache 的管理难题,并聚焦显存分配、淘汰策略、跨请求共享三大方向,带你掌握现代推理引擎的高效设计思想。

知识前提:你需要了解 Transformer 的自注意力机制,知道每个 Token 会生成 Key 和 Value 张量,以及自回归解码时如何复用前缀。对 GPU 显存结构(HBM、碎片化)有基本概念会更容易理解。


显存分配:从预留到动态分页

KV Cache 需要一块连续显存来存放每个序列层、每个注意力头的 Key 和 Value。分配方式直接决定显存利用率和系统吞吐。

静态预留:最简单的起步

早期实现(如 HuggingFace Transformers)在推理前预设一个最大序列长度,相乘得出每个序列需要的总字节数,并将整块连续显存预先划分给该序列。这种方式实现简单,但缺陷明显:

  • 显存碎片严重:每个请求按最大长度预留,导致大量未使用空间被浪费。
  • 并发能力受限:显存大小固定的 GPU 上,可同时处理的请求数被最大值锁死,无法动态伸缩。

动态分配:请求级弹性

更先进的引擎(如 FasterTransformer)允许在请求到来时才按当前序列长度分配所需显存,序列变长时再扩增。这减少了一些预留浪费,但仍面临内部碎片和重组开销。

分页管理(PagedAttention):革命性的思路

vLLM 借鉴操作系统虚拟内存的分页思想,提出了 PagedAttention。它将 KV Cache 划分成固定大小的物理“块”(block),序列的 KV Cache 则由多个不连续的块构成。

  • 核心收益

    • 显存零浪费:仅按需分配物理块。
    • 即时回收:请求结束后,释放的块可立即服务于其他请求。
    • 弹性扩展:序列增长可申请新块,无需拷贝原有数据。
  • 实践细节
    块大小(block size)通常设为 16 或 32 个 Token。块表(block table)记录逻辑块到物理块的映射,计算注意力时内核会动态解析映射,实现高效的不连续读取。vLLM 正是基于此将吞吐量提升数倍。

初学者提示:你可以把“块”理解为一本活页笔记本的纸张,序列顺序通过目录维护,物理上纸张可以来自不同本子,用完一张加一张,回收后还能给别人用。

统一虚拟寻址与碎片整理

即便分页管理,长时间运行后仍可能因块分配不均产生外部碎片。一些系统(例如 LMDeploy 的 Turbomind)采用统一虚拟地址和异步碎片整理,在尾部空闲时迁移块,保证大块请求的成功率。


淘汰策略:当显存不够用时

当物理块池耗尽,必须有策略选择“牺牲”哪些块来腾出空间。淘汰策略的核心是在延迟和吞吐间做权衡。

基础策略:FIFO 与 LRU

  • FIFO(先进先出):最早分配的块被优先回收。这对同等优先级的请求相对公平,但可能中断用户正在进行的“长对话”。
  • LRU(最近最少使用):记录每个块的最后访问时间,淘汰最久未被触及的块。对于突发请求或对话间歇期更友好,但需要维护时间戳开销。

请求级淘汰:换出与重计算

块淘汰通常不是独立发生,而是作用于整个序列。当需要为高优先级请求腾出空间时,策略可能换出某个低优先级序列的全部或部分块,触发重计算

  • 换出(Swap-out):将块数据拷贝到 CPU 内存或更慢的存储,显存立即可用。
  • 重计算(Recomputation):下次调度该序列时,根据保留的上下文 Token 重新计算被换出的 KV 内容。重计算带来的延迟增加需要纳入调度决策。

vLLM 的调度器支持基于优先级的抢占,高优请求可抢占低优请求的显存块,低优请求被换出或终止。

基于代价的淘汰算法

更精细化的方式是把每个序列当前的“代价”量化。例如:

  • 恢复成本:重计算该序列需消耗的 GPU 算力。
  • 等待时间:序列已在队列中待了多久。
  • 生成进度:已生成的 Token 数越多,丢弃的代价越大。

综合这些因子,构建一个优先级队列,淘汰综合代价最小的序列。这样在保证紧急请求的同时,尽量不伤害长序列用户的体验。


跨请求共享:让缓存“所见略同”

KV Cache 共享是进一步提升显存效率和降低首发延迟的关键。当多个请求的前缀一致时,它们完全可以共用一套 Key 和 Value。

前缀感知缓存(Prefix Caching)

很多场景会出现长公共前缀:

  • LLM 应用的系统提示词(system prompt)在每个交互中固定不变。
  • 批量请求同一文档的问答、摘要。
  • 多轮对话中共享的历史轮次。

实现机制:引擎以块为单位识别内容是否已缓存。vLLM 通过哈希 Token 序列来匹配块,当新序列的某一块与现有缓存内容完全相同,则直接引用该物理块,避免重复计算。

  • 块级匹配:通常比较一个块内所有 Token 的哈希值。若完全匹配,新序列的块表直接指向该物理块,引用计数加一。
  • 变量前缀处理:当匹配到不同块后,后续块无法共享,需要为新序列分配独立块。

跨序列并行共享

在多请求并行推理时,共享缓存还需要解决并发读写问题。常见的做法是:

  • 引用计数与写时复制:每个物理块维护一个引用计数。当所有引用序列仅为读取时,共享安全。一旦某一序列需要修改(实际 KV 生成不会修改已填块,但逻辑上可能存在边界情况),则复制一个新块,避免数据污染。
  • 异步引用管理:内核在写入新块前原子增引用,释放时原子减并决定是否回收。

多模态与跨样本复用

在多模态大模型中,图像特征通过交叉注意力融入序列,其 KV 缓存也可以复用。当多个问题基于同一张图,图像部分的 KV 可以被所有问题共享,大幅降低图像计算开销。

此外,投机解码(Speculative Decoding)中的草稿模型 KV 缓存也可复用主模型的某些层,实现更激进的加速。


工程落地:三大框架的对比视野

理解了理论,我们快速看看它们在主流引擎中的实现差异:

管理维度 vLLM (PagedAttention) LMDeploy (Turbomind) Text Generation Inference (TGI)
分配模型 物理块固定大小,块表连续 类似分页,支持动态块大小 连续预留 + 动态分桶
淘汰策略 抢占 + 重计算 / 换出 基于时间片的抢占,支持 CPU 卸载 优先级抢占 + 重计算
前缀共享 哈希匹配块级共享 自动识别并共享前缀块 支持 system prompt 缓存
特色设计 高效内核 FlashInfer 加速寻址 推理时自动碎片整理 与 HuggingFace 生态深度整合

选型建议:vLLM 是目前社区最活跃的分页 KV Cache 实现,适合高吞吐在线服务;LMDeploy 在长序列和量化场景表现优异;TGI 部署兼容性最好,适合快速集成。


总结:从显存到体验的闭环

KV Cache 管理本质是一场多维度的资源博弈。分页分配解决了空间浪费,淘汰策略平衡了公平与效率,跨请求共享则从根本上减少了冗余计算。对于开发者而言,理解这些机制不仅有助于调优线上服务,还能在设计应用时主动利用前缀共享(如固定系统提示词、批量处理),让推理引擎发挥出极限表现。

未来,随着模型架构演进(如多 Query 注意力、混合精度 KV Cache 压缩),缓存管理会更加精细化。掌握本节所述的核心理念,你将能快速适应这些新变化,成为大模型部署的实践专家。