Woosuk Kwon, Zhuohan Li, Siyuan Zhuang, Ying Sheng, Lianmin Zheng, Cody Hao Yu, Joseph E. Gonzalez, Hao Zhang, Ion Stoica
UC Berkeley
vLLM introduces PagedAttention, an attention algorithm inspired by operating-system virtual memory and paging, that fundamentally changes how LLM serving systems manage the key-value (KV) cache. By dividing the KV cache into fixed-size blocks that need not be contiguous in physical GPU memory, PagedAttention achieves near-zero memory waste and enables flexible memory sharing across sequences—delivering 2–4× throughput improvements over prior systems such as FasterTransformer and Orca.
KV cache has OS-process-like behavior: it grows dynamically, has an unknown lifetime, and can be shared. Treat it like virtual memory with paging.
PagedAttention: an attention kernel that operates on non-contiguous KV blocks mapped via a block table—exactly like page tables map virtual to physical memory.
Near-zero waste (96.3% effective utilization vs. 20.4% in prior systems), enabling far larger batches and higher throughput.
In autoregressive LLM serving, each request requires storing key and value tensors for every previously generated token—the KV cache. For a 13B-parameter model (OPT-13B), a single token's KV cache occupies 800 KB (2 × 5120 × 40 × 2 bytes), and a full 2048-token sequence can require up to 1.6 GB. On an A100 GPU with 40GB RAM, roughly 65% goes to model parameters, leaving only ~30% for KV cache—the critical bottleneck.
Orca (Max): only 20.4% of KV cache memory stores actual token states. vLLM achieves 96.3%.
vLLM adopts a centralized scheduler with distributed GPU workers. The KV Cache Manager manages memory via block tables, analogous to how an OS kernel manages page tables. GPU workers only see physical block IDs—they never need to reason about memory sharing or fragmentation.
Traditional attention requires keys and values stored contiguously in memory. PagedAttention partitions the KV cache into blocks, each holding B tokens' keys and values. During attention computation, the kernel fetches blocks from non-contiguous physical locations via the block table, computing attention block-by-block.
For a sequence of length i, denote the key block
Kj = (k(j-1)B+1, ..., kjB) and value block
Vj similarly. The attention computation becomes block-wise:
// Block-wise attention computation (Equation 4 from the paper)
// B = block size (default 16 tokens per block)
// For each key block j = 1 ... ceil(i/B):
Aij = exp(qiT Kj / sqrt(d)) / sum(exp(qiT Kt 1 / sqrt(d)), t=1..ceil(i/B))
// Final output is weighted sum over value blocks:
oi = sum(Vj AijT, j=1..ceil(i/B))
// Key difference: kernel identifies and fetches DIFFERENT KV blocks
// from non-contiguous physical memory using the block table.
// Each GPU warp processes one block for coalesced memory access.
Unlike prior systems that pre-allocate max-length contiguous chunks, vLLM allocates physical blocks one at a time as the sequence grows. A new physical block is only allocated when the last logical block is full. This limits internal fragmentation to at most one block per sequence (the last, partially filled block).
When multiple sequences share a common prefix (parallel sampling, beam search), their logical blocks map to the same physical blocks with reference counts > 1. A copy is only triggered when a sequence tries to write to a shared block. This is identical to OS copy-on-write for forked processes.
vLLM serves requests in arrival order to prevent starvation. When GPU memory is exhausted, the latest request is preempted first (preserving fairness for earlier arrivals).
Swapping: Evict KV blocks to CPU RAM via PCIe (all-or-nothing per sequence). Recomputation: Discard blocks and regenerate KV cache from the prompt + generated tokens. Better for small block sizes.
Multiple samples from one prompt share the prompt's KV blocks. Only divergent generation blocks are separate. Saves 6–10% memory.
Beam candidates share blocks dynamically as the tree evolves. Candidates that are pruned have their blocks freed immediately. Saves 37–55% memory.
System prompts and few-shot examples are cached as shared physical blocks. New requests map their logical blocks to these cached blocks (copy-on-write protected). Achieves up to 3.6× higher throughput.
vLLM is implemented in ~8.5K lines of Python and ~2K lines of C++/CUDA. The block manager and scheduler are in Python; the PagedAttention kernel and block operations are fused CUDA kernels.
# Conceptual block table structure (per sequence)
# Maps logical block index -> (physical_block_id, num_filled, ref_count)
class BlockTable:
"""Maps logical KV blocks to physical blocks in GPU DRAM."""
def __init__(self, block_size: int = 16):
self.block_size = block_size # tokens per block (B)
self.entries: List[BlockEntry] = []
def append_token(self, allocator: BlockAllocator):
"""Called for each new token generated."""
if not self.entries or self.entries[-1].is_full():
# Last block is full -> allocate a NEW physical block
phys_block = allocator.allocate()
self.entries.append(BlockEntry(phys_block, num_filled=1))
else:
# Room in current block -> just increment counter
self.entries[-1].num_filled += 1
def get_physical_ids(self) -> List[int]:
"""Returns physical block IDs for the attention kernel."""
return [e.physical_block_id for e in self.entries]
# When a sequence writes to a block shared by others (ref_count > 1)
def cow_write(block_entry: BlockEntry, allocator: BlockAllocator):
"""Copy-on-write: fork a new physical block if shared."""
if block_entry.ref_count > 1:
# Shared block -> copy to new physical block
old_phys = block_entry.physical_block_id
new_phys = allocator.allocate()
cuda_block_copy(src=old_phys, dst=new_phys) # fused kernel
block_entry.physical_block_id = new_phys
block_entry.ref_count = 1
allocator.dec_ref(old_phys) # decrement old block's ref
# ref_count == 1 -> write directly, no copy needed
// Conceptual structure of the PagedAttention CUDA kernel
// Three fused operations minimize kernel launch overhead:
// 1. Fused Reshape & Block Write
// New KV cache is split into blocks, reshaped for coalesced reads,
// and saved at positions specified by the block table.
// 2. Fused Block Read & Attention
// Each GPU warp reads one KV block from the block table,
// computes partial attention scores, then reduces across warps.
__global__ void paged_attention_kernel(
const float* query, // [num_heads, head_dim]
const float* key_cache, // [num_blocks, block_size, num_heads, head_dim]
const float* value_cache, // [num_blocks, block_size, num_heads, head_dim]
const int* block_tables, // [num_seqs, max_blocks_per_seq]
const int* seq_lens, // [num_seqs]
float* output // [num_seqs, num_heads, head_dim]
) {
// Each warp handles one KV block for one attention head
int block_idx = block_tables[seq_id * max_blocks + logical_block];
// Fetch K, V from physical block_idx (non-contiguous!)
// Compute softmax(Q * K^T / sqrt(d)) * V per block
// Reduce partial results across blocks
}
// 3. Fused Block Copy (for CoW)
// Batches all pending copy operations into a single kernel launch.
# vLLM supports all decoding via three sequence operations:
fork(seq) # Create new sequence sharing parent's KV blocks
# Used for: parallel sampling, beam search branching
append(seq) # Add new token to sequence (may allocate block or trigger CoW)
# Used for: every autoregressive decode step
free(seq) # Release sequence's blocks (decrement ref counts)
# Used for: completed sequences, pruned beam candidates
| Configuration | vs. FasterTransformer | vs. Orca (Oracle) | vs. Orca (Max) |
|---|---|---|---|
| OPT-13B, 1 GPU, ShareGPT | up to 22× | 1.7–2.7× | 2.2–4.3× |
| OPT-66B, 4 GPUs, ShareGPT | -- | 1.7–2.7× | 2.7–8× |
| OPT-175B, 8 GPUs, ShareGPT | -- | 1.7–2.7× | 2.7–8× |
| OPT-13B, 1 GPU, Alpaca | up to 22× | 1.7–2.7× | 2.2–4.3× |
| # Output Sequences | Memory Saved |
|---|---|
| 2 | 6.1% |
| 4 | 8.5% |
| 6 | 9.8% |
| Beam Width | Memory Saved |
|---|---|
| 2 | 37.6% |
| 4 | 53.1% |
| 6 | 55.2% |
The PagedAttention kernel is 20–26% slower than FasterTransformer's contiguous attention kernel due to block table lookups, extra branches, and handling variable sequence lengths. However, this only affects the attention operator, not other layers (FFN, LayerNorm, etc.). The end-to-end throughput improvement from better memory utilization far outweighs this overhead.
| Block Size | ShareGPT Perf. | Alpaca Perf. | Trade-off |
|---|---|---|---|
| 1–4 | Poor | Poor | Too small: low GPU parallelism, high table overhead |
| 16 (default) | Optimal | Optimal | Best balance of utilization vs. internal fragmentation |
| 32–128 | Good | Degraded | Larger blocks increase internal frag for short sequences |
| 256 | Degraded | Poor | Too large: approaches contiguous allocation behavior |
While PagedAttention is foundational, its design targets single-request serving within a single session. Modern agentic AI systems expose several gaps:
PagedAttention shares KV blocks within a single request (parallel sampling, beam search) but has no mechanism to cache and reuse blocks across different requests. Every new request recomputes its KV cache from scratch. Agentic systems that issue many requests with shared prefixes (system prompts, tool schemas) waste significant computation.
Addressed later by: SGLang RadixAttention, Mooncake KVCache-centric disaggregation
vLLM uses an all-or-nothing eviction policy: when memory is exhausted, it evicts all blocks of a sequence. There is no LRU/LFU cache with partial eviction or intelligent retention of high-value prefixes. This limits performance for workloads with temporal locality (e.g., multi-turn agents revisiting contexts).
Addressed later by: CacheBlend, Epic, InfiniGen
While vLLM supports tensor-parallel execution across GPUs within a node, the KV cache manager is centralized. There is no cross-node KV cache transfer, disaggregated storage, or distributed caching tier. This limits scalability for cloud-scale agentic deployments.
Addressed later by: Mooncake, MemServe, InfiniStore
FCFS scheduling treats all requests equally regardless of their KV cache sharing potential. An agentic scheduler could co-locate requests with shared prefixes, reorder to maximize cache hits, or prioritize high-value continuations.
Addressed later by: SGLang, CachedAttention, MemServe
All KV blocks are stored at full precision (FP16). There is no compression, quantization, or selective retention. For long-context agentic interactions (100K+ tokens), this becomes prohibitively expensive.
Addressed later by: CacheGen, KIVI, Gear, DMC
Prefill (compute-bound) and decode (memory-bound) phases run on the same GPUs, creating resource contention. Agentic systems with variable-length inputs could benefit from separating these phases onto specialized hardware.
Addressed later by: Splitwise, DistServe, Mooncake
PagedAttention is arguably the single most influential systems contribution to LLM serving. Its impact extends across three dimensions:
The insight that KV cache management is isomorphic to OS virtual memory management unlocked decades of systems research (paging, CoW, swapping, reference counting) for direct application to GPU memory in LLM serving. This analogy continues to guide new research.
By March 2026, vLLM has 48K+ GitHub stars and is the default serving engine for most LLM deployments. Its block-based KV cache design has been adopted by TensorRT-LLM, SGLang, and virtually every production serving system.
The block table abstraction cleanly separates the logical view (sequences see contiguous KV) from the physical view (GPU DRAM uses scattered blocks). This separation enables all downstream innovations: caching, compression, disaggregation, and scheduling can all operate at the block level without changing the attention computation.
This survey exists because PagedAttention created the block-based vocabulary that all subsequent papers use. "KV blocks," "block tables," "physical vs. logical," "reference counting," "copy-on-write"—these concepts, introduced here, are the shared language of every paper analyzed in this survey.
8.5K lines of Python + 2K lines of C++/CUDA (original paper). Supports OPT, GPT, LLaMA, and many other model architectures. Built on FastAPI frontend with OpenAI-compatible API.
Published at SOSP '23 (Symposium on Operating Systems Principles), October 23–26, 2023, Koblenz, Germany. ACM ISBN 979-8-4007-0229-7/23/10.
| Component | Language | Description |
|---|---|---|
| Frontend | Python (FastAPI) | OpenAI-compatible API; user-configurable sampling params and beam width |
| Scheduler | Python | Centralized FCFS scheduler with preemption; manages block tables |
| Block Manager | Python | CPU + GPU block allocators; reference counting; CoW tracking |
| PagedAttention Kernel | C++/CUDA | Fused reshape-write, block-read-attention, and block-copy kernels |
| Model Executor | Python (PyTorch) | Supports GPT, OPT, LLaMA; uses NCCL for tensor parallelism |
| Distributed | Python + NCCL | Megatron-LM style SPMD tensor parallelism across GPUs |