microsoft / microsoft/vscode

Multi-diff editor retains disposed row DOM across input changes

Open
#335,719 1 comment 0 reactions 1 assignee Claimed by @hediet View on GitHub
bug multi-diff-editor
Dominant language
TypeScript
Stars
193k
Forks
42.4k
PR merge metrics
PR metrics pending

Description

Does this issue occur when all extensions are disabled?: N/A — reproduced in isolated browser diagnostics with no extension host; not separately reproduced via the installed app's UI.

- VS Code Version: 1.138.0-insider, `7b7e49c83affacfac726040280da69b4999f3e01` (2026-09-11). Diagnostics used `33a6a088236067e1a16d08481d617dfcf6da2e2c`; affected code is identical.
- OS Version: macOS 26.6.2, arm64; headless Chromium diagnostics.

Steps to Reproduce:

1. In a browser harness, create a real compact `MultiDiffEditorWidget` at 900×640 with 90 two-sided text diffs using `MultiDiffEditorInput`, real model services, and a synthetic text-model resolver. Collapse all before `setViewModel`, yielding about 20 row templates.
2. Keep the widget alive. Call `setViewModel(undefined)`, dispose the input, load another 90-file input, and repeat three times. Count `.multiDiffEntry` elements after each clear.

**Observed:** retained row DOM grows **20 → 35 → 50 → 65**. Each cleared state has zero text models and only five cached templates/ten live label listeners. Disposed rows remain attached until the entire widget is disposed.

**Expected:** disposed templates remove their DOM; only the five intentionally cached templates remain after clearing.

**Cause / fix direction:** [`DiffEditorItemTemplate` appends its root](https://github.com/microsoft/vscode/blob/7b7e49c83affacfac726040280da69b4999f3e01/src/vs/editor/browser/widget/multiDiffEditor/diffEditorItemTemplate.ts#L287) but never removes it on disposal. The [pool disposes excess templates](https://github.com/microsoft/vscode/blob/7b7e49c83affacfac726040280da69b4999f3e01/src/vs/editor/browser/widget/multiDiffEditor/virtualizedItemManager.ts#L251-L293), leaving their DOM behind. Register root removal with the template's lifetime, **not** with unbinding, since pooled templates are reused. A temporary isolation experiment kept retained DOM at five across the same cycles.

Add regression coverage for DOM counts after repeated input replacement and pool eviction. This is actual DOM retention, distinct from the bounded listener-count warning in #206959.

Relevant pool/lifecycle history: https://github.com/microsoft/vscode/commit/10de1b9343662a4043258b418630481e27c863b1 (@hediet).

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.