The Linear Memory

The WebAssembly specification defines the linear memory as a contiguous, byte-addressable memory region used by Wasm programs to read and write data.

The linear memory is composed of the following sections:

  • Main Stack: Used for temporary allocations and to store some local variables. The stack grows downward (toward lower memory addresses).

  • Static Data: Contains statically linked constants and global variables.

  • Malloc Heap (optional): Used for dynamic memory allocations. The malloc heap grows upward (toward upper memory addresses).

The linear memory is allocated in the Managed Heap when the WasmModule is instantiated and zero-initialized (once). Each Wasm Module declares its own linear memory. The following figure illustrates the Managed Heap layout.

../../_images/linear-memory-overview.png

Managed Heap Overview with Wasm Module Linear Memory

The linear memory is available in the Java host as an array of bytes (byte[]). See Access Managed C Memory from Java for more details.

Note

The Managed Heap size must be greater than the sum of the linear memory sizes allocated by all Wasm Modules.

Note

In Multi-Sandbox mode, the sum of the linear memory sizes allocated by all Wasm Modules in a Feature must be lower than the Feature memory limit configured by the Kernel (if any).

Configure the Linear Memory Layout

MicroEJ recommends linking a Wasm module using the -Wl,--stack-first linker option.

Thus, you will get the following memory layout:

../../_images/linear_memory_layout.png

Wasm Linear Memory Layout

This ensures that both main stack overflows and malloc heap overflows trigger an exception when accessing out-of-bounds memory.

Configure the Linear Memory Size

The WebAssembly specification organizes the linear memory in pages, where each page is 64 KB (65,536 bytes). This page-based structure has been designed for efficient memory allocation and potential growth during runtime for large environments. However, the minimum page size (64KB) is not suitable for constrained embedded environments, where memory resources are limited.

MicroEJ implementation allocates the linear memory once at module startup and is not dynamically resized. The memory.grow instruction always fails and returns -1.

By default, the size of the linear memory is initialized with the Wasm module initial number of pages. The Wasm module initial number of pages can be configured using the -Wl,--initial-memory=[size_in_bytes] linker option. The given size must be a multiple of 64KB, i.e. a number of pages.

The Wasm module can also declare a maximum number of pages, using the -Wl,--max-memory=[size_in_bytes] linker option. If the Wasm module declares a maximum, it must be equal to the initial number of pages, because the linear memory never grows. Otherwise, the SOAR rejects the Wasm module. So if you set -Wl,--max-memory, give it the same value as -Wl,--initial-memory.

The size of the linear memory can be reduced below 64KB if both of the following conditions are met:

  • the Wasm module does not embed neither the memory.size nor the memory.grow instructions. This is the case if the C code does not transitively calls the malloc implementation declared in WASI libc.

  • the Wasm module exports the __heap_base global using the -Wl,--export=__heap_base linker option.

In this case, the linear memory is initialized to the value of the __heap_base global, which represents the sum of the main stack size and the static data size.

Configure the Main Stack Size

By default, the main stack size is initialized to 65536. You can adjust the main stack size to using the -z stack-size=[size_in_bytes] linker option.

Configuration Examples

The following Managed C code declares a static array of 100 bytes, and does not embed neither the memory.size nor the memory.grow instructions.

char my_static_data[100];

The C code is compiled with the following options: -Wl,--no-entry -nostdlib -Wl,--export-all -Wl,--stack-first.

The next table shows the impacts of additionnal options on the allocated linear memory size:

Extra Options

Required Size

(bytes)

Allocated Size

(bytes)

Comments

none

65636

131072

By default, the main stack size is initialized to 65536. The required linear memory size is greater than one page, so it is aligned on 2 pages.

-Wl,--initial-memory=262144

262144

262144

The linear memory size is set to the Wasm module initial number of pages (4 pages).

-z stack-size=512

612

65536

The main stack size is initialized to 512, but the Wasm module does not export the __heap_base symbol. The linear memory size is aligned on 1 page.

-z stack-size=512 -Wl,--export=__heap_base

612

612

The linear memory size is set to the value of the __heap_base global (512 bytes of main stack + 100 bytes of static data).