fix: null out effect.b in destroy_effect to prevent memory leak (#17980)

## Fix: #17881

### Root Cause

When a dynamic component switches (e.g. `<Component />`), branch effects
are destroyed via `destroy_effect()`.

However, the `effect.b` (Boundary reference) field was not cleared
alongside other references (`next`, `prev`, `ctx`, `deps`, `fn`,
`nodes`, `ac`).

As a result, destroyed effects retained a reference to the `Boundary`
instance, which holds references to component state and child effects.
This prevented destroyed component subtrees from being garbage
collected, causing memory usage to grow during repeated component
switching.

### Solution

Clear the boundary reference during effect destruction.

```diff
effect.next =
      effect.prev =
      effect.teardown =
      effect.ctx =
      effect.deps =
      effect.fn =
      effect.nodes =
      effect.ac =
+     effect.b =
          null;
```

### Test Plan

* All existing tests pass:

  * runtime-runes: 2,459
  * runtime-legacy: 3,294
  * signals: 96
  * Total: 5,849 tests

* Added a dynamic component switching test that toggles components
repeatedly and verifies correct DOM output.

### Validation

Reproduced the issue using the example from #17881.

After applying the fix:

* Memory usage stabilizes during repeated component switching
* Destroyed components are properly reclaimed by the garbage collector
* No behavioral regressions observed

### Impact

* Fixes memory leak in dynamic component switching
* Minimal, safe change
* No API or behavior changes

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
pull/17965/head
Nitin Sahu 5 months ago committed by GitHub
parent 6b33dd2a1e
commit 8e4de9b145
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: null out `effect.b` in `destroy_effect`

@ -559,6 +559,7 @@ export function destroy_effect(effect, remove_dom = true) {
effect.fn =
effect.nodes =
effect.ac =
effect.b =
null;
}

Loading…
Cancel
Save