Skip to content

Draw the whole chain from a GC root, however long it is - #2954

Merged
pyricau merged 1 commit into
mainfrom
why-do-long-paths-display-gc-r
Aug 11, 2026
Merged

Draw the whole chain from a GC root, however long it is#2954
pyricau merged 1 commit into
mainfrom
why-do-long-paths-display-gc-r

Conversation

@pyricau

@pyricau pyricau commented Aug 11, 2026

Copy link
Copy Markdown
Member

A chain past twenty steps was cut at the root end, and the head row said GC root: …, then … 14 steps instead of the objects. That answers "what holds this?" with a count of the objects that would have said, in the one pane that exists to answer it, and there is no way from the count back to them. Independent paths — the other ways a stretch of a chain could have run — were cut at fifteen for the same non-reason.

Chains get long: on the dumps in this repo the deepest are 499 steps (large-dump.hprof) and 1,518 (compose_leak.hprof), both walks down a linked structure.

What the cut was protecting was the drawing, not the reading:

  • Reading is a heap dump read per step — 6 ms for the 499-step chain, 12 ms for the 1,518-step one, against a hover's budget of a hundred.
  • Drawing was the real cost. The pane was a Column in a verticalScroll, which composes every row, and a chain of 1,500 rows at four lines each never appeared at all — 60 s and nothing on screen. It is a LazyColumn now: the pane composes the seven rows it has the height for, and a chain of 500 steps takes the same ~200 ms from the click as one of 20.
  • The stretches that could have run otherwise are still asked per chain, and a chain that long has almost none — the deep ones are linked lists, where every step dominates the object. One detour and 18 ms for the 499, none at all for the 1,518.

Numbers came from throwaway tests over large-dump.hprof and compose_leak.hprof, deleted before this landed; they're recorded in notes/decisions.md.

Tests: the core test that pinned the cut now pins the whole chain, and the UI test for a chain taller than its pane asserts the off-screen row doesn't exist rather than isn't displayed, which is what a lazy pane means. shark-explorer-core:check and shark-explorer-app:check are green.

🤖 Generated with Claude Code

A chain past twenty steps was cut at the root end and the head row said
"GC root: …, then … 14 steps" instead. That answers "what holds this?"
with a count of the objects that would have said, in the one pane that
exists to answer it, and there is no way from the count back to them.

Chains get long. On the dumps in this repo the deepest are 499 steps
(large-dump.hprof) and 1,518 (compose_leak.hprof), both walks down a
linked structure, so this is not a rare shape.

What the cut was protecting was the drawing, not the reading. Reading
one is a heap dump read per step: 6 ms for the 499 and 12 ms for the
1,518, against a hover's budget of a hundred. Drawing was the problem —
the pane was a Column in a verticalScroll, which composes every row, and
a chain of 1,500 rows at four lines each never appeared at all: 60 s and
nothing on screen. It is a LazyColumn now, so the pane composes the seven
rows it has the height for and a chain of 500 steps takes the same 200 ms
from the click as one of 20.

The independent paths a stretch of a chain could have run instead lose
their cut too, for the same reason: a way of holding an object that stops
short is the same non-answer. A chain that long has almost no stretches
in doubt anyway — the deep ones are linked lists, where every step
dominates the object, one detour and 18 ms for the 499 and none for the
1,518.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@pyricau
pyricau merged commit efe9826 into main Aug 11, 2026
16 checks passed
@pyricau
pyricau deleted the why-do-long-paths-display-gc-r branch August 11, 2026 13:39
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

Successfully merging this pull request may close these issues.

1 participant