Skip to content

Commit c40fd13

Browse files
committed
Fix memory leak hotspots
- render: alias the root Fragment's props.children to its diffed _children so in-place rerenders release replaced vnode generations instead of pinning the first render's tree (#4909, #4905) - unmount: null vnode._children and component._globalContext so a retained unmounted vnode/component can't keep the subtree's vnode shells or the ancestor provider chain alive
1 parent 82ed24e commit c40fd13

2 files changed

Lines changed: 15 additions & 2 deletions

File tree

src/diff/index.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,10 @@ export function unmount(vnode, parentVNode, skipRemove) {
654654
}
655655
}
656656

657-
r.base = r._parentDom = NULL;
657+
// Also drop the context chain: an unmounted component instance is often
658+
// kept alive by user code (subscriptions, timers, devtools), and should
659+
// not pin every ancestor provider through _globalContext.
660+
r.base = r._parentDom = r._globalContext = NULL;
658661
}
659662

660663
if ((r = vnode._children)) {
@@ -673,7 +676,10 @@ export function unmount(vnode, parentVNode, skipRemove) {
673676
removeNode(vnode._dom);
674677
}
675678

676-
vnode._component = vnode._parent = vnode._dom = UNDEFINED;
679+
// Null _children as well: a single retained unmounted vnode (e.g. held in
680+
// user code or an ancestor's props.children) should not chain the entire
681+
// unmounted subtree's vnode shells.
682+
vnode._component = vnode._parent = vnode._dom = vnode._children = UNDEFINED;
677683
}
678684

679685
/** The `.render()` method for a PFC backing instance. */

src/render.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ export function render(vnode, parentDom, replaceNode) {
6666

6767
// Flush all queued effects
6868
commitRoot(commitQueue, vnode, refQueue);
69+
70+
// Alias the root Fragment's props.children to its diffed _children. The
71+
// props object is created by us above and never observable by user code.
72+
// In-place rerenders (renderComponent) swap vnodes in the _children array;
73+
// without this alias, props.children would pin the first render's entire
74+
// vnode tree in memory for the lifetime of the root. See #4909 / #4905.
75+
vnode.props.children = vnode._children;
6976
}
7077

7178
/**

0 commit comments

Comments
 (0)