Skip to content

Instantly share code, notes, and snippets.

@lydell
Created July 21, 2024 18:03
Show Gist options
  • Save lydell/c7b93d0ad9c31139d12c187389486653 to your computer and use it in GitHub Desktop.
Save lydell/c7b93d0ad9c31139d12c187389486653 to your computer and use it in GitHub Desktop.
Explains why elm-watch has been leaking memory when hot reloading, and how to fix it.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>elm-watch garbage collection</title>
</head>
<body>
<script>
(function (scope) {
var heavy = Array.from({ length: 1000 }, () =>
Array.from({ length: 1000 }, () => Math.random())
);
var view = function () {
console.log(heavy.length);
};
var app = {
view: view,
};
scope.Elm = {
Main: {
init: function () {
// Remove the closure scope of `f` and only let it access the passed things.
// This works because functions created with `new Function` don’t have access to
// the local scope, only the global scope.
function scopeHack(f, names, values) {
return new Function(...names, "return " + f.toString())(
...values
);
}
var stepper = function () {
app.view();
};
stepper = scopeHack(stepper, ["app"], [app]);
var hotReload = function (newApp) {
// Even though we re-assign the only reference to `view` that we use,
// `view` is still in closure scope (of `stepper` and `hotReload`)
// and won’t be garbage collected. Then `heavy` won’t be garbage collected either.
// `scopeHack` solves this problem: it removes the closure scope of `view` and `heavy`.
app.view = newApp.view;
stepper();
};
hotReload = scopeHack(
hotReload,
["app", "stepper"],
[app, stepper]
);
setInterval(stepper, 1000);
return {
hotReload: hotReload,
};
},
},
};
})(this);
var app = window.Elm.Main.init();
setTimeout(() => {
app.hotReload({
view: function () {
console.log("updated"); // Doesn’t reference `heavy`.
},
});
Elm.Main.init = function () {
console.log("new init");
};
}, 5000);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment