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

Memory leaks in WASM #352

Closed
oblique opened this issue Jul 26, 2024 · 2 comments · Fixed by #356
Closed

Memory leaks in WASM #352

oblique opened this issue Jul 26, 2024 · 2 comments · Fixed by #356

Comments

@oblique
Copy link
Member

oblique commented Jul 26, 2024

Currently there are memory leaks in WASM and it looks like a limitation of WASM, but we need further investigation.

Useful information:

@oblique
Copy link
Member Author

oblique commented Aug 1, 2024

I just ruled out that this could be a memory fragmentation on the Rust side.

Rust allocates a single continuous memory region my using memory_grow instruction. That memory region is then used by dlmalloc to provide Rust's global allocation. When dlmalloc uses all the memory of that region, it calls memory_grow again to allocate more space. Whatever is allocated by memory_grow can not be freed. I used memory_size to check how much memory was purely allocated for Rust.

After an hour or so, browser's task manager was showing 3GB of memory consumption by Lumina tab. However the memory region that was used by Rust was at 103mb, almost from the beginning of the syncing. This concludes that memory leaks are tightly related to JavaScript's types.

oblique added a commit to oblique/lumina that referenced this issue Aug 1, 2024
`tracing_web::performance_layer` was causing high memory consumption
because browser was keeping high resolution data for each tracing event.

Fixes eigerco#352 and eigerco#353
@oblique
Copy link
Member Author

oblique commented Aug 2, 2024

After reading JS Objects in Rust from wasm-bindgen's internal design documentation I ruled out the posibility that memory leak is happening because of Rust not freeing JS objects.

I was printing wasm_bindgen::externref_heap_live_count every 1 minute. In case of memory leak, that value should have constantly increasing to a huge number over time, which didn't happen.


After ruling out the above, I couldn't understand why memory consumption of Lumina's tab was increasing and even becoming more than 3GB.

Throughout all my investigation I was using Allocation instrumentation on timeline of Chrome, trying to pin point the leak. While doing that I was ignoring Performance, PerformanceMark, and PerformanceMeasure from the allocations, thinking that they existed because of the instrumentation.

I started checking random things to find any other clues about the leak, including of reading code of wasm-bindgen generated file lumina_node_wasm.js. Then I notice this:

    imports.wbg.__wbg_mark_6045ef1772587264 = function() { return handleError(function (arg0, arg1, arg2) {
        getObject(arg0).mark(getStringFromWasm0(arg1, arg2));
    }, arguments) };
    imports.wbg.__wbg_mark_bad820680b8580c2 = function() { return handleError(function (arg0, arg1, arg2, arg3) {
        getObject(arg0).mark(getStringFromWasm0(arg1, arg2), getObject(arg3));
    }, arguments) };
    imports.wbg.__wbg_measure_1d846b814d43d7e1 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6) {
        getObject(arg0).measure(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4), getStringFromWasm0(arg5, arg6));
    }, arguments) };
    imports.wbg.__wbg_measure_7ca0e5cfef892340 = function() { return handleError(function (arg0, arg1, arg2, arg3) {
        getObject(arg0).measure(getStringFromWasm0(arg1, arg2), getObject(arg3));
    }, arguments) };
    imports.wbg.__wbg_performance_72f95fe5952939b5 = function() {
        const ret = globalThis.performance;
        return addHeapObject(ret);
    };

Which indicates that our Rust code at some point is using Performance.mark() and Performance.measure(). I started looking on our dependencies and found that tracing-web is using it in its performance layer. After checking our initialization of tracing-web, I realized that we are actually enabling the performance layer, so I commented it out.

After doing that, memory consumption stopped increasing to that huge numbers! 🥳

Note that this is not really a memory leak, but it is how performance marks work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants