Open
Description
It appears that every time we execute our widget, a new copy of the module is instantiated, and subsequently leaked.
You can replicate this with a module that includes a large const such as:
import anywidget
import traitlets
class LeakyWidget(anywidget.AnyWidget):
_esm = """
const buffer = new ArrayBuffer(100000000);
function render({ model, el }) {
let div = document.createElement("div");
div.innerHTML = `Buffer is is ${buffer.byteLength} bytes.`;
el.classList.add("leaky-widget");
el.appendChild(div);
}
export default { render };
"""
_css = """
.leaky-widget button { background-color: #ea580c; }
"""
value = traitlets.Int(0).tag(sync=True)
Repeatedly executing LeakyWidget()
in a cell will leak ~100MB per run.
You can see this in a browser tool inspector by taking snapshots after each execution of the cell and seeing newly created ModuleEnvironmentObject
s:
Ideally, we would have some mechanism to simply cache and re-use the same module across all widget instances, but it would be acceptable for them to at least get freed correctly.