Bug 250569 - Terminated worker memory leak
Summary: Terminated worker memory leak
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: Safari Technology Preview
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2023-01-13 06:10 PST by Jake Archibald
Modified: 2024-01-31 04:53 PST (History)
12 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jake Archibald 2023-01-13 06:10:35 PST
Not sure this is the correct component. This bug is something to do with workers/js/wasm.

1. Go to https://safari-worker-memory-leak-demo.netlify.app
2. Click "draw using threads", and wait for the result. Repeat this step around 20 times.

I start getting "rangeerror: Out of memory".

Each run of "draw using threads" spins up a worker, which in turn starts other workers. The root worker is terminated once the operation is complete.

I wonder if the inner workers are not being correctly collected when the parent worker terminates.
Comment 1 Ahmad Saleem 2023-01-13 12:04:25 PST
Is this an issue STP160 or before? Because this landed - https://github.com/WebKit/WebKit/commit/0987e578a6a8813156f74ebbf01490e4d31aa8f8

Related to workers termination, which can cause this?
Comment 2 Ahmad Saleem 2023-01-13 13:08:05 PST
(In reply to Jake Archibald from comment #0)
> Not sure this is the correct component. This bug is something to do with
> workers/js/wasm.
> 
> 1. Go to https://safari-worker-memory-leak-demo.netlify.app
> 2. Click "draw using threads", and wait for the result. Repeat this step
> around 20 times.
> 
> I start getting "rangeerror: Out of memory".
> 
> Each run of "draw using threads" spins up a worker, which in turn starts
> other workers. The root worker is terminated once the operation is complete.
> 
> I wonder if the inner workers are not being correctly collected when the
> parent worker terminates.

Just to update - I can reproduce this in Safari Technology Preview 161 and get 'Unhandled Promise Rejection: RangeError: Out of memory' in Console.
Comment 3 Jake Archibald 2023-01-15 05:26:01 PST
Might be noteworthy: refreshing the page doesn't seem to release the memory either.
Comment 4 Radar WebKit Bug Importer 2023-01-20 06:11:17 PST
<rdar://problem/104473516>
Comment 5 Ahmad Saleem 2023-01-22 13:23:45 PST
(In reply to Ahmad Saleem from comment #1)
> Is this an issue STP160 or before? Because this landed -
> https://github.com/WebKit/WebKit/commit/
> 0987e578a6a8813156f74ebbf01490e4d31aa8f8
> 
> Related to workers termination, which can cause this?

I did local revert on WebKit trunk by undoing changes of this commit and build WebKit release and use Comment 0 test case but I still got "rangeerror: Out of memory", so I think this change is not culprit or regression (if this is regression).

Just wanted to update my testing result since I was conscious of my change, so I wanted to confirm, it is not caused by it.
Comment 6 Sam Verschueren 2023-03-15 01:23:23 PDT
Just want to step in here to say that I see the exact same behaviour when testing StackBlitz WebContainers (https://blog.stackblitz.com/posts/introducing-webcontainers/) in the latest Safari Technology Preview.

We spin up quite some worker (in combination with wasm) and after running some projects and refreshing the page, I also see the `RangeError: Out of Memory`. Just like Jake indicated, refreshing the page does not release the memory and I basically have to close the browser entirely.

When the error happens, and I try to create a memory object in the DevTools console like this, it also throws.

> new WebAssembly.Memory({initial:10, maximum:65535, shared:true})

However, if I set the `maximum` to something much lower like `10`, it works.

So I tried constructing those memory objects in a loop and see if it crashes at some point, but I was able to easily create 300.000 of those objects.
Comment 7 Sam Denty 2023-04-19 14:10:19 PDT
Until a fix for this lands, this can be worked around by doing the following:

1. Create a cloudflare worker with the following:

```js
export default {
  async fetch(request, env) {
    let url
    try {
      url = new URL(decodeURIComponent(new URL(request.url).search.slice(1)))
    } catch {
      return new Response("must provide a url", { status: 404 })
    }

    url.searchParams.set('memory-freed', 1)

    return Response.redirect(url, 302);
  }
}
```

2. Server-side: On the page using WASM & Workers, if the URL doesn't contain the query string `memory-freed` do a 302 redirect to `https://WORKER_NAME.USER.workers.dev/?${url_with_query_string}`

3. Worker with above code will redirect back to page with `memory-freed=1` in the URL

4. Server-side: use middleware that detects the `memory-freed=1` in requests, and inject at the top of the document the following:

```
<script>{ const url = new URL(location.href); url.searchParams.delete('memory-freed'); history.replaceState(null, '', url) }</script>
```


5. TADA, this bug is worked around!
Comment 8 Ivan Čurić 2024-01-31 04:48:04 PST
(In reply to Jake Archibald from comment #0)
> Not sure this is the correct component. This bug is something to do with
> workers/js/wasm.
> 
> 1. Go to https://safari-worker-memory-leak-demo.netlify.app
> 2. Click "draw using threads", and wait for the result. Repeat this step
> around 20 times.
> 
> I start getting "rangeerror: Out of memory".

@Jake, could you share the source code for this?

On iPhone 13, running iOS 16.7.1 I am unable to run even a single render using 4 threads. After booting up https://rreverser.com/wasm-bindgen-rayon-demo/ in another tab (which doesn't exhibit this issue), your demo runs out of memory during the wasm load.

Might be related to https://bugs.webkit.org/show_bug.cgi?id=222097
Comment 9 Jake Archibald 2024-01-31 04:53:49 PST
I agree that https://bugs.webkit.org/show_bug.cgi?id=222097 sounds the same.

Ugh, sorry, but I don't have access to the source code. It was just a quick hack on a laptop I no longer own.