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

Consumers can unexpectedly hold unused memory in dependencies #254

Open
DavidANeil opened this issue Jan 22, 2025 · 0 comments
Open

Consumers can unexpectedly hold unused memory in dependencies #254

DavidANeil opened this issue Jan 22, 2025 · 0 comments

Comments

@DavidANeil
Copy link

DavidANeil commented Jan 22, 2025

Using this mock example

const listOfSignals = new Signal.State([]);

const sumOfList =  new Signal.Computed(() => {
    let sum = 0;
    for (const node of listOfSignals.get()) {
        sum +=  node.get();
    }
    return sum;
});
const watcher = new Signal.subtle.Watcher(() => {});
watcher.watch(sumOfList);

{
    const tempSignal = new Signal.state(3)
    listOfSignals.set([tempSignal]);
}

assert(sumOfList.get() === 3);

listofSignals.set([]);
// 

At the end of this mock code sumOfList is currently "dirty", but it still internally holds a reference to tempSignal as a producer dependency, if it were to recalculate it would be able to drop that dependency, and allow the memory to be freed, I have a few ideas for how this could be resolved.

Idea 1) Use WeakRef to store producers

This would allow the memory to be freed, so the internals don't hold memory longer than the computation closure.
Cons:

  • Doesn't help if the cached return value itself is holding memory
  • In my experiments, this significantly hurt runtime performance

It is possible that, similar to #252 we might learn that engine native code is able to accomplish this without significant performance penalties.

Idea 2) Add a free method to Computed signals to return them to their original state

When invoked, this will mark all consumers as dirty, then reset the node to the original state it had when the object was born: no cached values, no consumers, no producers.
This could allow a framework to free memory of all signals that have been stale for a certain amount of time.
Cons:

  • Requires somewhat manual intervention to free up unused memory

Idea 2.5) Grant authority in the spec for the host to invoke free on any dirty signals, at its own discretion

When a browser is in a high memory pressure scenario, or has extra compute to spend it could be permitted to do what frameworks do: free memory for all signals that have been stale for a certain amount of time.
Cons:

  • Significantly alters the user contract with the Signal API: Signals can now recompute even when no dependencies changed.

I am also open to other ideas that allow signals to be have a more intuitive memory profile.

@DavidANeil DavidANeil changed the title Consumers can unexpectedly hold unused memories in dependencies Consumers can unexpectedly hold unused memory in dependencies Jan 23, 2025
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

No branches or pull requests

1 participant