A module often reads a linear memory shared with its JavaScript host. Bytes move through typed views; pointer and length values identify regions inside the module allocation. A safe wrapper checks bounds, owns allocation and release, and copies results before freeing memory that backs them. On ordinary non-shared memory, growth replaces the buffer and old JavaScript views become detached. That detail breaks code that stores one Uint8Array for an entire editing session. A pointer is not a durable object identifier.
Wasm Linear Memory, Ownership, and Copy Cost
Working case
The scan tool crops an image into tiles. Tile 29 is copied into a module allocation, processed, copied back to a fresh JavaScript buffer, and then released. Another scan needs more pages of memory; the module grows, so the wrapper obtains a new view before reading tile 47. The first reviewer closes the editor halfway through; a finally block releases the allocation and revokes any object URL. The server never sees the pixel buffer, and the UI can discard the result on account switch.
Implementation boundary
function validRegion(offset, length, capacity) {
return Number.isSafeInteger(offset) && Number.isSafeInteger(length) && offset >= 0 && length >= 0 && offset <= capacity && length <= capacity - offset;
}
console.log(validRegion(47, 62, 100));
// Output: falsePut allocation, range check, call, copy-out, and release behind one adapter function. Check that offset and length are safe integers and that offset plus length remains within the current buffer. Treat an exported allocator and deallocator as one matched pair; do not free memory the host does not own. Recreate typed views after any operation that can grow ordinary memory. A shared-memory build has different view behavior and concurrency constraints, so document it separately. Limit input dimensions before calculating byte counts to avoid overflow and device exhaustion.
Cost and boundaries
Copy-in and copy-out are O(n) in bytes even when the module algorithm is faster than its JavaScript equivalent. Peak memory can include the source file, decoded image, module memory, output copy, and canvas backing store at once. A nominal 47-megabyte file can expand considerably when decoded into pixels. Partition work into bounded tiles and release each one. Measure peak resident memory and long-task duration alongside throughput. Zero-copy claims require proof that lifetime and ownership are safe.
Failure trace
A cached Uint8Array points to a detached buffer after memory growth, and the second crop reads zero bytes. A different wrapper frees an output pointer before copying its bytes, so results vary with later allocations. Test forced growth, maximum-size inputs, zero-length slices, near-end offsets, allocation failure, cancellation, repeated scans, and simultaneous edits. For privacy, ensure discarded buffers are no longer reachable from application state; freeing a pointer alone does not guarantee secret erasure.
Verification
- Every module allocation has one owner and release path.
- Views are refreshed after ordinary memory growth.
- Offset and length are checked before reads or writes.
Practice drill
Process tiles sized 47 and 62 units through an adapter that forces one memory growth between calls. Compare bytes before and after the growth, then recreate the view. Inject an allocator failure and verify every earlier allocation is released. Record peak memory for one large scan and compare tiled processing with a whole-image copy. Finally switch accounts and inspect whether any pixel buffer remains attached to a component or worker message.
Decision note
Wrap the pointer boundary once, cap allocations, and price byte copies as part of the algorithm.
Common Mistakes
- Keeping a stale typed view after growth.
- Returning a view after freeing its backing region.
- Comparing compute time while ignoring copy and decode cost.
Connected lessons
Build Project: bounded local scan analysis and review Web Development: browser compute and peer sessions quiz; follow WebAssembly and Browser Compute; Wasm Loading, Artifact, and Fallback Contract; Wasm Worker Jobs, Cancellation, and Result Order; Wasm Capabilities, Isolation, and Performance Budget; Cooperative Main-Thread Scheduling; Upload Intake Budgets and Storage Ownership.
