Stream: wasmtime

Topic: how to discard memory in wasmtime?


view this post on Zulip Srayan Jana (Oct 23 2025 at 08:00):

I’m aware that this isn’t part of the wasm spec yet (see https://github.com/WebAssembly/design/issues/1397
https://github.com/WebAssembly/memory-control/issues/7)
But is there some sort of unofficial wasmtime extension or something to detect when memory isn’t being use and shrink it?

Hi all, after a video call with google last week, I was encouraged to raise a conversation here around issues we at Unity have with Wasm memory allocation. The short summary is that currently Wasm ...
Hi! I think it would be better to put the memory.discard instruction into a separate proposal. Grouping this instruction with other features is not strictly necessary and slows down the work on it....

view this post on Zulip Notification Bot (Oct 23 2025 at 09:43):

This topic was moved here from #general > how to discard memory in wasmtime? by Till Schneidereit.

view this post on Zulip Till Schneidereit (Oct 23 2025 at 09:54):

There isn't, no. Wasmtime doesn't do unofficial extensions, because those fracture the ecosystem. As documented here, we have strict requirements for shipping functionality

view this post on Zulip Srayan Jana (Oct 23 2025 at 18:27):

O okay, so in the meantime, do you just set a maximum for heap memory and just never go past that?

view this post on Zulip Alex Crichton (Oct 23 2025 at 18:54):

A ResourceLimiter and/or pooling allocator configuration settings can be used to limit memory growth, yes

view this post on Zulip Alex Crichton (Oct 23 2025 at 18:54):

Once memory is allocated to an instance though there's no way to make it go away

view this post on Zulip Alex Crichton (Oct 23 2025 at 18:54):

without deallocating the whole store that is

view this post on Zulip fitzgen (he/him) (Oct 23 2025 at 19:25):

In general, because allocating new instances is fast (~5 microseconds), the recommended method for reclaiming a Wasm instance's memory is to simply discard the Store and Instance and then create new ones when new work comes in (e.g. a new HTTP request)

view this post on Zulip Celarye (Oct 23 2025 at 20:22):

I personally use static variables to keep some in memory state for my components which I need throughout the whole runtime, example:

static CONTEXT: LazyLock<Plugin> = LazyLock::new(|| Plugin {
    http_client: HttpClient::new(),
    storred_settings: RwLock::new(PluginStoredSettings {
        ...
    }),
    stats: RwLock::new(PluginStats {
        ...
    }),
});

So I think that in my case dropping and recreating the Store and Instance would not really be ideal :sweat_smile:. I assumed the GC proposal was supposed to help with this down the line, but this is not yet implemented for the component-model?

view this post on Zulip Chris Fallin (Oct 23 2025 at 20:26):

under the hood our GC implementation also does not free/discard memory, though you're right that semantically the spec allows that (garbage is unreachable by definition so it would be unobservable to reclaim backing store).

Our usual answer for expensive pre-initialized state is either instance reuse if your security threat model tolerates it (wasmtime now has a knob for this for wasip3 at least, as of recently, IIRC?) or pre-initialization and snapshotting with a tool like Wizer; then the initial state from the PoV of the core Wasm engine already has that state baked in.

view this post on Zulip Pat Hickey (Oct 23 2025 at 20:54):

instance reuse if your security threat model tolerates it (wasmtime now has a knob for this for wasip3 at least, as of recently, IIRC?)

the new knob is specific to wasmtime serve in the wasmtime-cli, but its functionality is built out of "ordinary" wasmtime crate functionality that can be built into any embedding

view this post on Zulip Chris Fallin (Oct 23 2025 at 20:56):

Right, sorry, to be clear -- one can do it in an ad-hoc way today; I just meant the ready-to-go option.

view this post on Zulip Chris Fallin (Oct 23 2025 at 20:57):

Also, just to make sure you're tracking all the options and dependencies @Celarye -- you mentioned GC as allowing memory reclamation, semantically; but presence of that proposal won't magically let guests written in, e.g., Rust, relinquish memory. You'd need a guest toolchain+language that specifically uses only GC objects (then one would need to do the engine work to reclaim backing after GC). Just want to make sure that's explicit :-)

view this post on Zulip Celarye (Oct 23 2025 at 22:56):

Hoh, I am not really sure what to do now.

To give some context as to what I am trying to achieve. I am writing a Discord bot and all of its functionality is covered by plugins (WASI components). At the moment I just re-use the same stores and instances per plugin throughout the whole runtime of the program. It would just run 24/7 and make many calls into those components.

But if I understand it correctly, those stores and instances never release memory and they will end up using more and more over time (even if in traditional programs this memory would be released)? Meaning I will need to have a way to clear the memory it has consumed but retain the global state (which I currently rely on for between calls).

view this post on Zulip Chris Fallin (Oct 23 2025 at 23:02):

those stores and instances never release memory and they will end up using more and more over time (even if in traditional programs this memory would be released)?

That's not the case: a program with a stable working set size should reach equilibrium with a stable memory footprint for the Store over time.

In more detail: a Wasm guest with a linear memory controls its own memory allocation; its linear memory is allocated by a malloc function inside the guest, typically. The component model canonical ABI gives a specified interface to this (cabi_realloc) so that the host can allocate buffers inside the guest to receive call arguments, etc. All memory so allocated will normally be freed. Of course, "freed" in this case means "returned to the allocator inside the linear memory". So the linear memory will never shrink (is not allowed to do so by spec), but it also will not grow without bound with a normal malloc/free/... loop.

view this post on Zulip Chris Fallin (Oct 23 2025 at 23:02):

To put it in traditional Unix terms: it's like a libc implementation of malloc that can mmap to get more chunks over time, but never returns those chunks to the OS. You can still malloc/free inside the process and reuse memory that way. "Process" maps to "Wasm instance" in this case.

view this post on Zulip Celarye (Oct 23 2025 at 23:08):

I see, thank you for explaining. I think I'm pretty happy with my current implementation then. I will however look into ResourceLimiter and/or pooling allocator configuration settings as well.

view this post on Zulip fitzgen (he/him) (Oct 24 2025 at 21:39):

Celarye said:

I am writing a Discord bot and all of its functionality is covered by plugins (WASI components). At the moment I just re-use the same stores and instances per plugin throughout the whole runtime of the program. It would just run 24/7 and make many calls into those components.

This makes sense and components for plugins is a good use case.

I personally would suggest architecting it so that the state lives/persists outside of the Instance and Store, and then create new Instances and Stores for each time a user on discord pings the bot, or some other event happens that the bot's plugins will respond to (e.g. a new commit was pushed to a github repo that the bot is following or whatever). This also allows you to persist that state in a sqlite database or something, which additionally lets you easily restart the bot's whole process or migrate to a new virtual server instance or whatever.

view this post on Zulip Celarye (Oct 24 2025 at 22:54):

The issue is that I do not really have an idea of what state a plugin may or may not have. I could maybe look into providing host functions to read/write serialized data from/to an SQLite database or so but I feel like this would worsen the DX a bit.

So at this moment it's completely up to the plugin developer to implement this, I've given them access to file I/O as well in the case using that benefits them.

Though I will have to look into this and see if there is a nicer way to solve this because I think recreating new Instances and Stores for each call is indeed what I want to work towards.

I am also not sure how this all will work once I switch to WASIp3. For example, can multiple calls be made to the same Store and Instance at the same time? But maybe that's another problem for later, when WASIp3 stabilizes. :laughing:


Last updated: Dec 06 2025 at 06:05 UTC