Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wasm GC doesn't seem to collect garbage which results in GC heap out of memory errors #9701

Open
Tracked by #5032
epsylonix opened this issue Dec 2, 2024 · 5 comments
Assignees
Labels
bug Incorrect behavior in the current implementation that needs fixing wasm-proposal:gc Issues with the implementation of the gc wasm proposal

Comments

@epsylonix
Copy link

epsylonix commented Dec 2, 2024

Test Case

Running Kotlin-compiled Wasm guest requires Wasm GC proposal to be implemented by the runtime and Wasmtime now officially supports Wasm GC since version 27.0.0.

I'm embedding Wasmtime in Go (Wasmtime version in wasmtime-go updated to 27.0.0 locally) and running a benchmark that calls a simple guest function which makes small heap allocations. A minimal Kotlin guest function that reproduces the issue looks like this:

@OptIn(UnsafeWasmMemoryApi::class)
@WasmExport("test")
fun test() {
    withScopedMemoryAllocator { allocator ->
            val ptr = allocator.allocate(16)
            ptr.storeInt(1)
        }
}

Running a benchmark which calls this this function from the host repeatedly results in GC heap out of memory error almost instantaneously. According to the discussion at #wamtime this might be caused by an issue with Wasm GC implementation in Wasmtime.

Expected Results

Kotlin's withScopedMemoryAllocator is supposed to free all the memory allocated during the function call so this function shouldn't cause GC to run out of memory.

Actual Results

Wasm guest execution fails with a GC heap out of memory error after several calls to the function.

Versions and Environment

Wasmtime version or commit: 27.0.0

Operating system: macOS

Architecture: arm64

Extra Info

It would be great to have more details in the documentation on how Wasm GC works in Wasmtime. For example, Wasm GC uses it's own memory but I can't find any documentation on the default size of it or whether it can be configured.

Edit: actually, MemoryAllocator doesn't rely on Wasm GC and uses linear memory instead so probably the GC heap out of memory error is not caused by allocator.allocate calls but by all the allocations Kotlin does automatically which do use Wasm GC heap.

@epsylonix epsylonix added the bug Incorrect behavior in the current implementation that needs fixing label Dec 2, 2024
@alexcrichton alexcrichton added the wasm-proposal:gc Issues with the implementation of the gc wasm proposal label Dec 3, 2024
@fitzgen
Copy link
Member

fitzgen commented Dec 4, 2024

Thanks for filing an issue! I just got back from vacation and am in the process of catching up on things.

To confirm: you are using the default collector (DRC) not the null collector?

FWIW, it is expected that the null collector will not collect garbage and allocation will eventually exhaust the GC heap.

The DRC collector is a reference-counting collector and does not have a cycle collector, so it is also expected to leak GC objects if they are part of cycles. This is fundamental. Additionally, at this moment the DRC collector does not yet transitively decrement reference counts, so many acyclic garbage objects will be leaked as well (eg with a cons list, only the head would be collected and not anything in the list's tail). This latter bit of leakage is not fundamental nor intended long term, it just reflects that this is a young, WIP implementation.

Final note: can you attach the .wasm or .wat file as a test case? This makes it easier for Wasmtime maintainers to debug and diagnose issues, since it removes needing to set up and invoke/understand/debug the Kotlin toolchain.

@epsylonix
Copy link
Author

Thank you! Yes, this was tested with the default DRC GC. Sure, will provide a .wasm file shortly.

@epsylonix
Copy link
Author

epsylonix commented Dec 5, 2024

Here is a .wasm file compiled using the code I've mentioned in the issue description. Calling the test function of the same module instance several times results in GC heap out of memory for me. withScopedMemoryAllocator makes allocations in linear memory so probably the issue can be reproduced without it.
gc_heap_out_of_mem.wasm.zip

Even if there is a memory leak, this code doesn't seem to produce a lot of garbage but it runs out of memory almost immediately. What is the size of the GC heap? Is it configurable?

@fitzgen
Copy link
Member

fitzgen commented Dec 5, 2024

What is the size of the GC heap? Is it configurable?

At the moment it has a fixed, fairly small capacity of 512KiB. This is just intended as a default for running tests. The plan is to have all the same knobs that linear memories have, we just haven't gotten there yet.

@fitzgen
Copy link
Member

fitzgen commented Dec 5, 2024

And thanks for attaching the wasm files!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Incorrect behavior in the current implementation that needs fixing wasm-proposal:gc Issues with the implementation of the gc wasm proposal
Projects
None yet
Development

No branches or pull requests

3 participants