memory leak in adapter node with unresolved promises
Describe the bug
Rendering a page that depends on a never-solving promise leaks memory.
Svelte seems to keep handlers around for the resolution of promises even after the page has been fully rendered and served to the client, preventing the js engine from freeing the associated memory.
Reproduction
https://github.com/lovasoa/sveltekit-memory-leak-bugreport
+page.svelte
<script>
import c from './const';
</script>
{#await c.waitForMe()}
<p>loading...</p>
{:then x}
<p>loaded {x}!</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
const.js
class MyClass {
constructor() {
this.x = neverSolve();
}
async waitForMe() {
const x = await this.x;
return x+1;
}
}
function neverSolve() {
return new Promise(()=>{});
}
export default new MyClass;
Logs
No response
System Info
System:
OS: Linux 6.2 Ubuntu 22.04.3 LTS 22.04.3 LTS (Jammy Jellyfish)
CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-11390H @ 3.40GHz
Memory: 1.03 GB / 15.36 GB
Container: Yes
Shell: 5.1.16 - /bin/bash
Binaries:
Node: 16.20.2 - /usr/bin/node
Yarn: 1.22.19 - /usr/bin/yarn
npm: 8.19.4 - /usr/bin/npm
pnpm: 8.6.3 - /usr/bin/pnpm
Browsers:
Chrome: 116.0.5845.187
npmPackages:
svelte: ^4.0.5 => 4.2.0
Severity
annoyance
Here are memory profiles from the example application, that can be examined with chrome devtools:
@dominikg , are you sure this belongs to sveltekit ? When I look at the code generated by svelte, it looks like it comes from there.
https://svelte.dev/repl/251d77ae3761440b95abde98df3a2d78?version=4.2.0
/* App.svelte generated by Svelte v4.2.0 */
import { create_ssr_component, escape, is_promise, noop } from "svelte/internal";
const App = create_ssr_component(($$result, $$props, $$bindings, slots) => {
const p = new Promise(() => {
});
return `${(function (__value) {
if (is_promise(__value)) {
__value.then(null, noop);
return ``;
}
return (function (x) {
return ` ${escape(x)} `;
})(__value);
})(p)}`;
});
export default App;
I'm not an expert, but the __value.then(null, noop) seems problematic to me. Doesn't it prevent deallocating __value even long after the component has been rendered ?
If we don't do that, any rejecting promise that's unhandled will (in recent versions of Node) crash the whole server. I don't know that we have another option than to try to handle it in some way.
any updates here?