并行采样的多条候选序列从同一 prompt 分叉时,它们的块表在初始阶段指向同一组存放 prompt KV cache 的物理块,系统用引用计数记录有多少个序列在共享这些块。某个序列生成与其它序列不同的 token 后,只为这个新的独有 KV 分配新块,并只更新该序列自己的块表,不复制整段前缀。共享前缀在显存里只存一份,直到没有任何序列引用它才回收,所以后续写入不会覆盖其它候选仍在读取的前缀。
这里要分清证据来源:vLLM 的 PagedAttention 论文确认系统实现了 KV cache 的近零浪费,并支持请求内与跨请求的灵活共享;块表映射、引用计数、按需分配这一套并行采样的具体流程,来自对 PagedAttention 机制的技术解析文章(博客园 SIo_2《从 KV-Cache 到 PagedAttention,揭秘 LLM 推理性能的全部细节》),并非论文原文的逐字表述。
共享的是物理块,不是前缀副本
PagedAttention 为每个请求维护一张独立的块表,记录该请求的每个逻辑块映射到显存中的哪个物理块。逻辑块是序列视角下连续的 KV 位置,物理块是显存里实际存放 KV 张量的单元,两者的对应关系由块表决定。这意味着序列的 KV 布局不是一段连续内存,而是一组可重新指向的块。
并行采样时,n 条候选序列如果各自保存一份完整 KV,显存占用会随候选数成倍增长;prompt 越长、并行度越高,增长越快。vLLM 的做法是让这 n 条候选的块表在初始阶段指向同一组存储 prompt KV cache 的物理块。共享发生在物理块这一层:候选序列各自的 token 序列仍然存在,但 KV 数据只有一份,块表是每序列独立的小型元数据。
分叉时写入新块,共享前缀不被覆盖
共享一旦建立,就必须回答一个问题:某条候选要写入自己的 KV 时,会不会写进大家共用的块里。这由引用计数和分配策略共同保证。
系统用引用计数追踪有多少个序列正在共享这些块。当某个序列生成与其它序列不同的 token、需要写入新的 KV 对时,系统并不复制整个历史,而是新分配一个块存放这份独有的 KV,只更新该序列自己的块表,让新增的条目指向新块;其它仍共享原前缀块的序列,其块表继续指向原来的共享块。写入落在新块上,共享块本身没有被改写,这就是“不互相污染”的实现方式。
回收同样由引用计数驱动:共享前缀在内存中只存一份,直到没有任何序列引用它时才被回收。候选序列陆续结束或继续分叉,引用计数随之变化,只有真正无人使用的块才会回到可分配状态。
需要标出这条描述的适用面。资料给出的是并行采样共享前缀这一场景的机制说明;beam search 的分支管理与块共享没有被这份资料单独讨论,不能把并行采样的结论直接搬到 beam search 上。共享块尚未写满时,写入是否触发对该块的复制,资料没有给出源码级细节,因此不能把“新分配块存独有 KV”扩写成所有写入路径的完整描述。
收益的量级与成立条件
论文报告的结果包括两点:vLLM 在 KV cache 内存上接近零浪费,并支持请求内与跨请求的共享;在相同延迟水平下,相比 FasterTransformer、Orca 等系统,把流行 LLM 的吞吐提升 2~4 倍。论文同时指出,这一改进在更长序列、更大模型和更复杂解码算法下更为明显。
这些数字来自论文的特定评测系统与负载,不是任意部署的保证。前缀共享能带来多少显存节省,取决于并行候选共享的前缀长度与并行度,具体量化未在资料中给出。技术解析文章把这种效果概括为内存成本从“乘法”关系变成“加法”关系,指的就是前缀部分不随并行度线性增长。
还有几处边界不应被填平。资料未给出具体 vLLM 版本、块大小默认值,也未说明这些配置在不同版本之间是否一致;引用计数归零回收在资料中分别出现在并行采样的描述和 Prefix Caching 的描述里,两者的上下文不同,不能合并成同一代码路径的完整时序。