Systems & Optimization2023intermediate11 min read

Efficient Memory Management for Large Language Model Serving with PagedAttention

إدارة الذاكرة بكفاءة لخدمة النماذج اللغوية الكبيرة باستخدام PagedAttention

Kwon, W. · Li, Z. · Zhuang, S. · Sheng, Y. · Zheng, L. · Yu, C. H. · Gonzalez, J. E. · Zhang, H. · Stoica, I. — SOSP

The problem

Serving large language models requires holding a key-value cache () in memory for every active request. This cache grows token by token during and its final size is unknown in advance. Existing systems reserve a contiguous memory block sized for the maximum possible , wasting 60–80% of precious GPU memory to , , and redundant duplication. This waste directly limits the — and therefore the — of the serving system.

The contribution

PagedAttention stores the KV cache in fixed-size blocks that can live anywhere in GPU memory, mapped through a — exactly like and in operating systems. This eliminates fragmentation and enables on-demand allocation. On top of it, the authors built vLLM, a serving system that achieves near-zero memory waste and supports sharing of KV cache blocks across sequences for parallel sampling and . vLLM improved throughput by 2–4× over FasterTransformer and Orca at the same .

The impact

PagedAttention became the industry standard for KV cache management in LLM serving. It is now the default memory manager in vLLM and has been adopted by TensorRT-LLM, Hugging Face TGI, and virtually every major framework. The paper reframed LLM serving as a memory-systems problem, importing decades of operating-system wisdom into machine learning infrastructure, and enabling the economic viability of large-scale LLM deployment.

Imagine a hotel that assigns every guest a presidential suite — whether they stay one night or a month — and won't let anyone else use the empty rooms. Most of the hotel sits dark while travelers camp in the lobby.

Now imagine the hotel switches to a system borrowed from apartment buildings: rooms are rented one at a time, they don't have to be next to each other, and a front-desk ledger maps each guest to their scattered rooms. The same hotel suddenly houses four times as many guests.

This paper brought exactly that idea — virtual memory and paging from operating systems — to the GPU memory that stores the KV cache during LLM serving.

The bottleneck: KV cache memory waste

When a large language model generates text, it produces one token at a time. At each step the model computes new key and value vectors for the mechanism. To avoid recomputing these vectors from scratch at every step, the system stores them in a key-value cache (KV cache). For a 13-billion-parameter model, a single request's KV cache can consume up to 1.7 GB of GPU memory.

The critical challenge is that the KV cache grows dynamically — one block of vectors per generated token — and its final size depends on the output length, which is unknown before generation finishes. Existing systems handle this by pre-allocating a contiguous memory region sized for the maximum possible sequence length. This causes three forms of waste.

First, internal fragmentation: the reserved region is almost always larger than the actual sequence, so the tail of each allocation is empty. Second, external fragmentation: as requests arrive and depart, the free memory becomes scattered into chunks too small for new allocations. Third, redundant duplication: techniques like parallel sampling and beam search generate multiple outputs from the same prompt, yet each copy stores its own full KV cache — even for the shared prefix.

Measurements on production systems show that these three wastes together consume 60–80% of KV cache memory. This directly limits the batch size, because fewer concurrent requests fit in GPU memory, which in turn reduces throughput.

Open in Lab
Drag the slider to see how much GPU memory is wasted under contiguous allocation. Internal fragmentation, external fragmentation, and duplication consume most of the available KV cache space.
The demo wakes as you arrive…

The insight: virtual memory for KV cache

Operating systems solved the exact same problem decades ago. In the 1960s, programs needed contiguous physical memory, which led to the same fragmentation nightmares. The solution was virtual memory with paging: give each program a contiguous logical address space, but map it to scattered physical pages through a page table. Programs see tidy consecutive addresses; the OS handles the messy physical layout.

PagedAttention imports this idea wholesale. Each request's KV cache is divided into fixed-size logical blocks (analogous to virtual pages). These logical blocks are mapped to physical blocks in GPU memory through a block table (analogous to a page table). The physical blocks do not need to be contiguous. The block manager allocates physical blocks on demand — one at a time — as new tokens are generated.

Think of it as giving each request a numbered notebook. The request writes on page 1, then page 2, then page 3. But page 1 might live on shelf A, page 2 on shelf G, and page 3 on shelf C. The block table is the index card that says "page 1 → shelf A, page 2 → shelf G, page 3 → shelf C." The request never notices the scattering.

Open in Lab
Click "Generate Token" to watch logical blocks map to scattered physical blocks through the block table. Notice how no contiguous allocation is needed.
The demo wakes as you arrive…

The PagedAttention algorithm

Standard attention computes a weighted combination of all value vectors, where the weights come from the dot product of the with each key. In a standard implementation, the keys and values for a single sequence are stored in contiguous tensors.

PagedAttention modifies the attention kernel so that keys and values are fetched block-by-block from non-contiguous physical locations. For each query vector, the kernel iterates through the block table, gathers the relevant key and value blocks, computes the partial attention within each block, and accumulates the result. The mathematical output is identical to standard attention — only the memory layout changes.

Concretely, let the block size be BB tokens. The KV cache for a sequence of length TT is divided into ⌈T/B⌉\lceil T/B \rceil blocks. For each attention head, the keys in block jj form a matrix Kj∈RB×dK_j \in \mathbb{R}^{B \times d} and the values form Vj∈RB×dV_j \in \mathbb{R}^{B \times d}, where dd is the head dimension. The attention for a single query qq is:

Attn(q)=∑j=1⌈T/B⌉esjmax⁡⋅(∑i=1Bjesji−sjmax⁡⋅Vji)∑j=1⌈T/B⌉esjmax⁡⋅(∑i=1Bjesji−sjmax⁡)wheresji=q⊤Kjid\text{Attn}(q) = \frac{\displaystyle\sum_{j=1}^{\lceil T/B \rceil} e^{s_j^{\max}} \cdot \left( \sum_{i=1}^{B_j} e^{s_{ji} - s_j^{\max}} \cdot V_{ji} \right)} {\displaystyle\sum_{j=1}^{\lceil T/B \rceil} e^{s_j^{\max}} \cdot \left( \sum_{i=1}^{B_j} e^{s_{ji} - s_j^{\max}} \right)} \quad\text{where}\quad s_{ji} = \frac{q^{\top} K_{ji}}{\sqrt{d}}
PagedAttention — block-wise attention with numerical stability — The query qq is dotted with keys KjiK_{ji} in each block jj to produce scores sjis_{ji}. Each block computes its local softmax using the block-maximum sjmax⁡s_j^{\max} for numerical stability. The results are then combined across blocks using the log-sum-exp trick. This produces mathematically identical results to standard attention but reads keys and values from non-contiguous physical blocks.
Open in Lab
Step through the PagedAttention algorithm: see the query gather keys from scattered physical blocks, compute partial attention per block, and combine results.
The demo wakes as you arrive…

vLLM: the serving system built on PagedAttention

vLLM is a complete LLM serving system that uses PagedAttention as its memory foundation. The architecture has three key components: a centralized scheduler that decides which requests to process at each step, a KV cache manager (block manager) that handles allocation and deallocation of physical blocks, and a set of GPU workers that execute the model with the PagedAttention kernel.

The scheduler implements (also called iteration-level scheduling): instead of waiting for an entire batch to finish before accepting new requests, it re-evaluates the active set at every single token-generation step. A request that finishes early immediately releases its blocks, and a new request can start in the same step. This eliminates the GPU idle time that plagued static batching.

The block manager tracks a free list of physical blocks, maintains reference counts for shared blocks, and performs copy-on-write when a shared block needs to be modified. It also handles : when GPU memory runs low, the scheduler can pause a lower-priority request by either swapping its blocks to CPU memory or simply freeing them for recomputation later. This ensures the system never deadlocks due to memory pressure.

Open in Lab
Watch the vLLM scheduler in action: requests arrive, get batched at each iteration, finish at different times, and new requests fill in immediately.
The demo wakes as you arrive…

Memory sharing: copy-on-write for parallel decoding

Many decoding strategies generate multiple output sequences from the same prompt. In parallel sampling, the model generates nn independent completions from the same input. In beam search, kk candidate sequences expand in parallel at each step. Both scenarios share a prefix: all sequences begin with the same prompt tokens and therefore share identical KV cache entries for those positions.

Without sharing, each sequence would duplicate the entire prompt's KV cache. With PagedAttention, all sequences point to the same physical blocks for the shared prefix. Only when a sequence needs to write a new token into a previously shared block does copy-on-write trigger: the system copies the block to a new physical location and updates that sequence's block table. This is identical to how Unix implements the fork() system call.

Measurements show 6–10% memory savings for parallel sampling and 37–55% savings for beam search. On the ShareGPT dataset with longer shared prefixes, savings reach up to 66% for beam search.

Open in Lab
Watch how forking a sequence shares physical blocks. When one sequence writes a new token, copy-on-write allocates a private copy only for the modified block.
The demo wakes as you arrive…

Results: 2–4× throughput improvement

The authors evaluated vLLM against two state-of-the-art baselines: NVIDIA's FasterTransformer and Orca (the system that introduced continuous batching). They tested on OPT models (13B and 175B parameters) with real conversation datasets (ShareGPT and Alpaca).

Under basic sampling, vLLM achieved 2–4× higher throughput than FasterTransformer and 1.7–2.7× higher than Orca, with the same or lower latency. The improvement grew with longer sequences and larger models, because memory pressure is more severe in those settings. Under beam search, the gains were even larger due to copy-on-write sharing.

Memory waste measurements confirmed the mechanism: existing systems wasted 60.4–80.3% of KV cache memory, while vLLM wasted less than 4%. The only remaining waste is internal fragmentation in the last block of each sequence, bounded by the block size BB.

Open in Lab
Compare serving throughput across systems. Toggle between basic sampling and beam search to see how memory sharing amplifies the gains.
The demo wakes as you arrive…

Under the hood: block table lookup

Simplified PagedAttention kernel — block table lookuppython

Simplified to show the idea — not the real implementation.

def paged_attention(query, key_cache, value_cache, block_table, block_size):
    """Compute attention over non-contiguous KV blocks."""
    d = query.shape[-1]
    num_blocks = len(block_table)

    # Accumulate weighted values across blocks
    output = zeros_like(query)
    total_exp = 0.0
    global_max = -inf

    for j in range(num_blocks):
        # Look up physical block from block table
        phys_block = block_table[j]
        K_j = key_cache[phys_block]    # shape: [B, d]
        V_j = value_cache[phys_block]  # shape: [B, d]

        # Compute attention scores for this block
        scores = query @ K_j.T / sqrt(d)  # shape: [B]
        block_max = max(scores)

        # Numerically stable accumulation
        correction = exp(global_max - max(global_max, block_max))
        exp_scores = exp(scores - max(global_max, block_max))

        output = output * correction + exp_scores @ V_j
        total_exp = total_exp * correction + sum(exp_scores)
        global_max = max(global_max, block_max)

    return output / total_exp

Timeline: from OS paging to LLM serving standard

  1. 1962

    Virtual memory invented

    Atlas computer at Manchester introduced virtual memory with paging, solving physical memory fragmentation for general-purpose programs.

  2. 2017

    Transformer architecture published

    "Attention Is All You Need" introduced the transformer, whose multi-head attention requires storing key-value pairs for all past tokens.

  3. 2022

    Orca introduces continuous batching

    Orca proposed iteration-level scheduling, allowing new requests to join a batch at each decoding step. However, it still used contiguous KV cache allocation.

  4. 2023

    PagedAttention and vLLM (this paper)

    Kwon et al. applied OS-style paging to KV cache management, achieving near-zero waste and 2–4× throughput improvement. Published at SOSP 2023.

  5. 2024

    PagedAttention becomes the industry norm

    TensorRT-LLM, Hugging Face TGI, SGLang, and MLC-LLM all adopted paged KV cache management. FlashAttention-2 was layered underneath for the compute kernel.

  6. 2025

    vAttention and beyond

    vAttention proposed keeping KV cache contiguous in virtual memory while using OS demand paging for physical allocation — keeping standard attention kernels unmodified. The paging paradigm continues to evolve.

PagedAttention's deepest contribution is not the 2–4× speedup — it is the reframing. Before this paper, LLM serving was treated as a pure ML systems problem. After it, the field recognized that memory management is the binding constraint, and that decades of OS research offer a ready toolkit. This shift in perspective opened the door to a generation of serving optimizations: prefix caching, radix attention, disaggregated prefill/decode, and — all of which build on the paged memory abstraction that this paper introduced.

CitationKwon, Li, Zhuang, Sheng, Zheng, Yu, Gonzalez, Zhang, Stoica. Efficient Memory Management for Large Language Model Serving with PagedAttention. SOSP, 2023.

Terms in this paper