Skip to content

Commit

Permalink
Detach sibling pointers in old child list
Browse files Browse the repository at this point in the history
When a fiber is deleted, it's still part of the previous (alternate)
parent fiber's list of children. Because children are a linked list, an
earlier sibling that's still alive will be connected to the deleted
fiber via its alternate:


  live fiber
  --alternate--> previous live fiber
  --sibling--> deleted fiber

We can't disconnect `alternate` on nodes that haven't been deleted
yet, but we can disconnect the `sibling` and `child` pointers.

Will use this feature flag to test the memory impact.
  • Loading branch information
acdlite committed Mar 23, 2021
1 parent 82c7916 commit f081a4b
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 262 deletions.
28 changes: 28 additions & 0 deletions packages/react-reconciler/src/ReactFiberCommitWork.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
enableScopeAPI,
enableStrictEffects,
enableStrongMemoryCleanup,
enableDetachOldChildList,
} from 'shared/ReactFeatureFlags';
import {
FunctionComponent,
Expand Down Expand Up @@ -2323,6 +2324,33 @@ function commitPassiveUnmountEffects_begin() {
detachFiberAfterEffects(alternate);
}
}

if (enableDetachOldChildList) {
// A fiber was deleted from this parent fiber, but it's still part of
// the previous (alternate) parent fiber's list of children. Because
// children are a linked list, an earlier sibling that's still alive
// will be connected to the deleted fiber via its `alternate`:
//
// live fiber
// --alternate--> previous live fiber
// --sibling--> deleted fiber
//
// We can't disconnect `alternate` on nodes that haven't been deleted
// yet, but we can disconnect the `sibling` and `child` pointers.
const previousFiber = fiber.alternate;
if (previousFiber !== null) {
let detachedChild = previousFiber.child;
if (detachedChild !== null) {
previousFiber.child = null;
do {
const detachedSibling = detachedChild.sibling;
detachedChild.sibling = null;
detachedChild = detachedSibling;
} while (detachedChild !== null);
}
}
}

nextEffect = fiber;
}
}
Expand Down
28 changes: 28 additions & 0 deletions packages/react-reconciler/src/ReactFiberCommitWork.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
enableScopeAPI,
enableStrictEffects,
enableStrongMemoryCleanup,
enableDetachOldChildList,
} from 'shared/ReactFeatureFlags';
import {
FunctionComponent,
Expand Down Expand Up @@ -2323,6 +2324,33 @@ function commitPassiveUnmountEffects_begin() {
detachFiberAfterEffects(alternate);
}
}

if (enableDetachOldChildList) {
// A fiber was deleted from this parent fiber, but it's still part of
// the previous (alternate) parent fiber's list of children. Because
// children are a linked list, an earlier sibling that's still alive
// will be connected to the deleted fiber via its `alternate`:
//
// live fiber
// --alternate--> previous live fiber
// --sibling--> deleted fiber
//
// We can't disconnect `alternate` on nodes that haven't been deleted
// yet, but we can disconnect the `sibling` and `child` pointers.
const previousFiber = fiber.alternate;
if (previousFiber !== null) {
let detachedChild = previousFiber.child;
if (detachedChild !== null) {
previousFiber.child = null;
do {
const detachedSibling = detachedChild.sibling;
detachedChild.sibling = null;
detachedChild = detachedSibling;
} while (detachedChild !== null);
}
}
}

nextEffect = fiber;
}
}
Expand Down
Loading

0 comments on commit f081a4b

Please sign in to comment.