← Back to Lessons Lesson 21 of 28
Intermediate data-structures

Wasm Memory Model

What is Linear Memory?

WebAssembly has a single, contiguous block of memory called linear memory. Think of it as a giant Vec<u8> that both Rust and JavaScript can read and write to.

Address:  0x0000    0x0100    0x0200    ...    0xFFFF
         ┌─────────┬─────────┬─────────┬──────┐
Memory:  │ stack   │ heap    │ data    │ ...  │
         │ data    │ allocs  │ section │      │
         └─────────┴─────────┴─────────┴──────┘
         └────────── 1 page = 64KB ───────────┘

Key properties:

  • Byte-addressable — every byte has an index (0, 1, 2, ...)
  • Pages — memory grows in 64KB pages (1 page = 65,536 bytes)
  • Shared — both Rust and JS can access the same bytes
  • Bounds-checked — accessing out-of-bounds memory traps (doesn't crash the browser)

How Rust Uses Linear Memory

When you compile Rust to Wasm, the compiler lays out memory like this:

┌──────────────┬──────────────┬──────────────┬──────────────┐
│ Static data  │ Stack        │ Heap         │ Free space   │
│ (strings,    │ (local vars, │ (Vec, String,│ (grows →)    │
│  constants)  │  call frames)│  Box allocs) │              │
└──────────────┴──────────────┴──────────────┴──────────────┘
0x0000                                                  0xFFFF...

Accessing Memory from JavaScript

JavaScript sees Wasm memory as an ArrayBuffer:

// After init(), wasm.memory is available
const memory = wasm.memory;

// Create typed views into the buffer
const bytes = new Uint8Array(memory.buffer);
const u32s = new Uint32Array(memory.buffer);
const f64s = new Float64Array(memory.buffer);

// Read a byte at address 1024
const value = bytes[1024];

// Write a float at address 2048 (byte offset)
f64s[2048 / 8] = 3.14;  // Float64Array index = byte offset / 8

Passing Data Between Rust and JS

Approach 1: Copy via wasm-bindgen (simple, safe)

#[wasm_bindgen]
pub fn process(data: &[u8]) -> Vec<u8> {
    // data is copied from JS to Wasm memory
    let mut result = data.to_vec();
    // ... modify result ...
    result  // copied from Wasm back to JS
}

Approach 2: Pointer + length (zero-copy, advanced)

#[wasm_bindgen]
pub struct Buffer {
    data: Vec<u8>,
}

#[wasm_bindgen]
impl Buffer {
    #[wasm_bindgen(constructor)]
    pub fn new(size: usize) -> Self {
        Self { data: vec![0; size] }
    }

    pub fn ptr(&self) -> *const u8 {
        self.data.as_ptr()
    }

    pub fn len(&self) -> usize {
        self.data.len()
    }
}
const buf = new Buffer(1024);
const ptr = buf.ptr();
const len = buf.len();

// Create a view directly into Wasm memory — zero copy!
const view = new Uint8Array(wasm.memory.buffer, ptr, len);

// Modify in place — Rust sees the changes
view[0] = 42;

Memory Growth

Wasm memory starts small and grows on demand:

// Rust triggers growth automatically when Vec/String needs more space
let mut big_vec = Vec::with_capacity(1_000_000); // may grow memory
// JS can check and grow manually
console.log(wasm.memory.buffer.byteLength); // current size
wasm.memory.grow(10); // grow by 10 pages (640KB)

// IMPORTANT: After grow(), all ArrayBuffer views are invalidated!
// Re-create views after growing:
const freshView = new Uint8Array(wasm.memory.buffer);

Common Pitfalls

Pitfall Why Fix
Stale ArrayBuffer views after memory growth memory.grow() detaches old buffer Re-create views after any operation that might grow
Alignment errors Float64Array needs 8-byte aligned offset Use ptr as usize % 8 == 0 check
Memory leaks Rust allocations not freed Drop structs properly, avoid forget() overuse
Reading freed memory Use-after-free via stale JS reference Copy data out before freeing Rust structs

Memory Size Budget

Content Typical size
Small Wasm module 50-200KB
Wasm + web-sys bindings 200KB-1MB
Default linear memory 1 page (64KB)
Large application 10-50MB
Browser limit ~2-4GB

Try It

Click Run to see linear memory concepts in action — creating memory, writing/reading at offsets, growing pages, and storing typed values.

Try It

Chapter Quiz

Pass all questions to complete this lesson