Course contentsShow
← Rust
Lesson 1236 of 1,91011. Asynchronous ProgrammingFree lesson

Memory Layout of Async Futures

Compare the stack and heap allocation requirements of anonymous futures versus boxed trait objects.

In this lesson, you will learn how the Rust compiler transforms anonymous async blocks into state machines and the memory trade-offs between stack-allocated futures and Box<dyn Future>.

The Anatomy of an Anonymous Future

When you write an async block, the compiler does not simply wrap your code in a function. Instead, it generates a hidden struct that acts as a state machine. Each local variable across an await point becomes a field in this struct.

Because the compiler knows the exact size of these variables at compile-time, it can calculate the total memory required for the future. Consequently, anonymous futures are usually stack-allocated—they are stored in the same way as a regular struct, making them incredibly lightweight.

async fn process() {
    let data = vec![1, 2, 3]; // Becomes a field in the generated struct
    some_io().await;          // Execution pauses, state is saved in the struct
    println!("{:?}", data);
}

The Cost of Boxed Futures

Sometimes, you cannot know the size of a future at compile-time (e.g., when returning different types of futures from a function via dyn Future). To handle this, we use Box::pin().

When you move a future into a Box, you are moving that state machine struct from the stack to the heap. This changes your memory layout in two ways:

  1. Indirection: Instead of a contiguous block on the stack, you now hold a pointer to a heap allocation.
  2. Dynamic Dispatch: Using Box<dyn Future> requires a vtable lookup every time poll is called, which adds a minor but measurable runtime overhead compared to the static dispatch of an anonymous future.

Why it Matters

If your future contains a large array, the stack-allocated state machine will be large. If you await many of these in a deeply nested tree, you risk a stack overflow. Conversely, heavy use of Box can lead to heap fragmentation and slower performance due to constant allocations.

Key Takeaway: Anonymous futures are statically-sized state machines allocated on the stack for maximum performance, while boxed futures move that state machine to the heap, trading minor allocation and indirection costs for the flexibility of dynamic type erasure.