microsoft / vscode

Visual Studio Code
https://code.visualstudio.com
MIT License
164.06k stars 29.23k forks source link

Memory leak in keybindings editor #202455

Closed SimonSiefke closed 5 months ago

SimonSiefke commented 9 months ago

Does this issue occur when all extensions are disabled?: Yes

Steps to Reproduce:

  1. Open the keybindings editor (Preferences: Open Keyboard Shortcuts)
  2. Close the keybindings editor
  3. Repeat opening and closing the keybindings editor a few more times
  4. Notice that the number of mouseout, dblclick, mousedown event listeners increases each time:
{
  "eventListenersWithStackTrace": [
    {
      "type": "mouseout",
      "description": "e => {\n                    dom_1.EventHelper.stop(e);\n                    element.classList.remove('active');\n                }",
      "objectId": "7535147866608838792.4.14647",
      "stack": [
        "listener (vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:103:80)",
        "new DomListener (vscode/out/vs/base/browser/dom.js:87:24)",
        "addDisposableListener (vscode/out/vs/base/browser/dom.js:101:16)",
        "vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:104:64",
        "Array.forEach (<anonymous>)",
        "ActionViewItem.render (vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:103:67)",
        "ActionViewItem.render (vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:205:19)",
        "vscode/out/vs/base/browser/ui/actionbar/actionbar.js:265:22",
        "Array.forEach (<anonymous>)",
        "ActionBar.push (vscode/out/vs/base/browser/ui/actionbar/actionbar.js:245:21)",
        "ActionsColumnRenderer.renderElement (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:722:36)",
        "TableListRenderer.renderElement (vscode/out/vs/base/browser/ui/table/tableWidget.js:46:26)",
        "PipelineRenderer.renderElement (vscode/out/vs/base/browser/ui/list/listWidget.js:938:26)",
        "ListView.insertItemInDOM (vscode/out/vs/base/browser/ui/list/listView.js:636:23)",
        "ListView._splice (vscode/out/vs/base/browser/ui/list/listView.js:426:26)",
        "ListView.splice (vscode/out/vs/base/browser/ui/list/listView.js:344:29)",
        "vscode/out/vs/base/browser/ui/list/splice.js:14:45",
        "Array.forEach (<anonymous>)",
        "CombinedSpliceable.splice (vscode/out/vs/base/browser/ui/list/splice.js:14:30)",
        "vscode/out/vs/base/browser/ui/list/listWidget.js:1187:67",
        "EventBufferer.bufferEvents (vscode/out/vs/base/common/event.js:1233:23)",
        "List.splice (vscode/out/vs/base/browser/ui/list/listWidget.js:1187:32)",
        "WorkbenchTable.splice (vscode/out/vs/base/browser/ui/table/tableWidget.js:155:23)",
        "KeybindingsEditor.renderKeybindingsEntries (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:465:39)",
        "KeybindingsEditor.render (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:417:22)",
        "async EditorPanes.doSetInput (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:313:17)",
        "async EditorPanes.doOpenEditor (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:180:44)",
        "async EditorPanes.openEditor (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:78:28)",
        "async vscode/out/vs/workbench/browser/parts/editor/editorGroupView.js:846:65",
        "async PreferencesService.openGlobalKeybindingSettings (vscode/out/vs/workbench/services/preferences/browser/preferencesService.js:253:33)",
        "async Object.accept (vscode/out/vs/platform/quickinput/browser/commandsQuickAccess.js:211:31)"
      ],
      "count": 50,
      "originalStack": ["vscode/src/vs/base/browser/ui/actionbar/actionViewItems.ts:159:57"],
      "originalName": null
    },
    {
      "type": "dblclick",
      "description": "e => {\n                dom_1.EventHelper.stop(e, true);\n            }",
      "objectId": "7535147866608838792.4.14643",
      "stack": [
        "listener (vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:99:95)",
        "new DomListener (vscode/out/vs/base/browser/dom.js:87:24)",
        "addDisposableListener (vscode/out/vs/base/browser/dom.js:101:16)",
        "ActionViewItem.render (vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:100:60)",
        "ActionViewItem.render (vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:205:19)",
        "vscode/out/vs/base/browser/ui/actionbar/actionbar.js:265:22",
        "Array.forEach (<anonymous>)",
        "ActionBar.push (vscode/out/vs/base/browser/ui/actionbar/actionbar.js:245:21)",
        "ActionsColumnRenderer.renderElement (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:722:36)",
        "TableListRenderer.renderElement (vscode/out/vs/base/browser/ui/table/tableWidget.js:46:26)",
        "PipelineRenderer.renderElement (vscode/out/vs/base/browser/ui/list/listWidget.js:938:26)",
        "ListView.insertItemInDOM (vscode/out/vs/base/browser/ui/list/listView.js:636:23)",
        "ListView._splice (vscode/out/vs/base/browser/ui/list/listView.js:426:26)",
        "ListView.splice (vscode/out/vs/base/browser/ui/list/listView.js:344:29)",
        "vscode/out/vs/base/browser/ui/list/splice.js:14:45",
        "Array.forEach (<anonymous>)",
        "CombinedSpliceable.splice (vscode/out/vs/base/browser/ui/list/splice.js:14:30)",
        "vscode/out/vs/base/browser/ui/list/listWidget.js:1187:67",
        "EventBufferer.bufferEvents (vscode/out/vs/base/common/event.js:1233:23)",
        "List.splice (vscode/out/vs/base/browser/ui/list/listWidget.js:1187:32)",
        "WorkbenchTable.splice (vscode/out/vs/base/browser/ui/table/tableWidget.js:155:23)",
        "KeybindingsEditor.renderKeybindingsEntries (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:465:39)",
        "KeybindingsEditor.render (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:417:22)",
        "async EditorPanes.doSetInput (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:313:17)",
        "async EditorPanes.doOpenEditor (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:180:44)",
        "async EditorPanes.openEditor (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:78:28)",
        "async vscode/out/vs/workbench/browser/parts/editor/editorGroupView.js:846:65",
        "async PreferencesService.openGlobalKeybindingSettings (vscode/out/vs/workbench/services/preferences/browser/preferencesService.js:253:33)",
        "async Object.accept (vscode/out/vs/platform/quickinput/browser/commandsQuickAccess.js:211:31)"
      ],
      "count": 25,
      "originalStack": ["vscode/src/vs/base/browser/ui/actionbar/actionViewItems.ts:154:69"],
      "originalName": null
    },
    {
      "type": "click",
      "description": "e => {\n                dom_1.EventHelper.stop(e, true);\n                // menus do not use the click event\n                if (!(this.options && this.options.isMenu)) {\n                    this.onClick(e);\n                }\n            }",
      "objectId": "7535147866608838792.4.14641",
      "stack": [
        "listener (vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:92:92)",
        "new DomListener (vscode/out/vs/base/browser/dom.js:87:24)",
        "addDisposableListener (vscode/out/vs/base/browser/dom.js:101:16)",
        "ActionViewItem.render (vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:93:60)",
        "ActionViewItem.render (vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:205:19)",
        "vscode/out/vs/base/browser/ui/actionbar/actionbar.js:265:22",
        "Array.forEach (<anonymous>)",
        "ActionBar.push (vscode/out/vs/base/browser/ui/actionbar/actionbar.js:245:21)",
        "ActionsColumnRenderer.renderElement (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:722:36)",
        "TableListRenderer.renderElement (vscode/out/vs/base/browser/ui/table/tableWidget.js:46:26)",
        "PipelineRenderer.renderElement (vscode/out/vs/base/browser/ui/list/listWidget.js:938:26)",
        "ListView.insertItemInDOM (vscode/out/vs/base/browser/ui/list/listView.js:636:23)",
        "ListView._splice (vscode/out/vs/base/browser/ui/list/listView.js:426:26)",
        "ListView.splice (vscode/out/vs/base/browser/ui/list/listView.js:344:29)",
        "vscode/out/vs/base/browser/ui/list/splice.js:14:45",
        "Array.forEach (<anonymous>)",
        "CombinedSpliceable.splice (vscode/out/vs/base/browser/ui/list/splice.js:14:30)",
        "vscode/out/vs/base/browser/ui/list/listWidget.js:1187:67",
        "EventBufferer.bufferEvents (vscode/out/vs/base/common/event.js:1233:23)",
        "List.splice (vscode/out/vs/base/browser/ui/list/listWidget.js:1187:32)",
        "WorkbenchTable.splice (vscode/out/vs/base/browser/ui/table/tableWidget.js:155:23)",
        "KeybindingsEditor.renderKeybindingsEntries (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:465:39)",
        "KeybindingsEditor.render (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:417:22)",
        "async EditorPanes.doSetInput (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:313:17)",
        "async EditorPanes.doOpenEditor (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:180:44)",
        "async EditorPanes.openEditor (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:78:28)",
        "async vscode/out/vs/workbench/browser/parts/editor/editorGroupView.js:846:65",
        "async PreferencesService.openGlobalKeybindingSettings (vscode/out/vs/workbench/services/preferences/browser/preferencesService.js:253:33)",
        "async Object.accept (vscode/out/vs/platform/quickinput/browser/commandsQuickAccess.js:211:31)"
      ],
      "count": 25,
      "originalStack": ["vscode/src/vs/base/browser/ui/actionbar/actionViewItems.ts:145:66"],
      "originalName": null
    },
    {
      "type": "mousedown",
      "description": "e => {\n                if (!enableDragging) {\n                    dom_1.EventHelper.stop(e, true); // do not run when dragging is on because that would disable it\n                }\n                if (this._action.enabled && e.button === 0) {\n                    element.classList.add('active');\n                }\n            }",
      "objectId": "7535147866608838792.4.14639",
      "stack": [
        "listener (vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:73:97)",
        "new DomListener (vscode/out/vs/base/browser/dom.js:87:24)",
        "addDisposableListener (vscode/out/vs/base/browser/dom.js:101:16)",
        "ActionViewItem.render (vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:74:60)",
        "ActionViewItem.render (vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:205:19)",
        "vscode/out/vs/base/browser/ui/actionbar/actionbar.js:265:22",
        "Array.forEach (<anonymous>)",
        "ActionBar.push (vscode/out/vs/base/browser/ui/actionbar/actionbar.js:245:21)",
        "ActionsColumnRenderer.renderElement (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:722:36)",
        "TableListRenderer.renderElement (vscode/out/vs/base/browser/ui/table/tableWidget.js:46:26)",
        "PipelineRenderer.renderElement (vscode/out/vs/base/browser/ui/list/listWidget.js:938:26)",
        "ListView.insertItemInDOM (vscode/out/vs/base/browser/ui/list/listView.js:636:23)",
        "ListView._splice (vscode/out/vs/base/browser/ui/list/listView.js:426:26)",
        "ListView.splice (vscode/out/vs/base/browser/ui/list/listView.js:344:29)",
        "vscode/out/vs/base/browser/ui/list/splice.js:14:45",
        "Array.forEach (<anonymous>)",
        "CombinedSpliceable.splice (vscode/out/vs/base/browser/ui/list/splice.js:14:30)",
        "vscode/out/vs/base/browser/ui/list/listWidget.js:1187:67",
        "EventBufferer.bufferEvents (vscode/out/vs/base/common/event.js:1233:23)",
        "List.splice (vscode/out/vs/base/browser/ui/list/listWidget.js:1187:32)",
        "WorkbenchTable.splice (vscode/out/vs/base/browser/ui/table/tableWidget.js:155:23)",
        "KeybindingsEditor.renderKeybindingsEntries (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:465:39)",
        "KeybindingsEditor.render (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:417:22)",
        "async EditorPanes.doSetInput (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:313:17)",
        "async EditorPanes.doOpenEditor (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:180:44)",
        "async EditorPanes.openEditor (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:78:28)",
        "async vscode/out/vs/workbench/browser/parts/editor/editorGroupView.js:846:65",
        "async PreferencesService.openGlobalKeybindingSettings (vscode/out/vs/workbench/services/preferences/browser/preferencesService.js:253:33)",
        "async Object.accept (vscode/out/vs/platform/quickinput/browser/commandsQuickAccess.js:211:31)"
      ],
      "count": 25,
      "originalStack": ["vscode/src/vs/base/browser/ui/actionbar/actionViewItems.ts:123:71"],
      "originalName": null
    },
    {
      "type": "-monaco-gesturetap",
      "description": "e => this.onClick(e, true)",
      "objectId": "7535147866608838792.4.14637",
      "stack": [
        "listener (vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:72:92)",
        "new DomListener (vscode/out/vs/base/browser/dom.js:87:24)",
        "addDisposableListener (vscode/out/vs/base/browser/dom.js:101:16)",
        "ActionViewItem.render (vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:73:60)",
        "ActionViewItem.render (vscode/out/vs/base/browser/ui/actionbar/actionViewItems.js:205:19)",
        "vscode/out/vs/base/browser/ui/actionbar/actionbar.js:265:22",
        "Array.forEach (<anonymous>)",
        "ActionBar.push (vscode/out/vs/base/browser/ui/actionbar/actionbar.js:245:21)",
        "ActionsColumnRenderer.renderElement (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:722:36)",
        "TableListRenderer.renderElement (vscode/out/vs/base/browser/ui/table/tableWidget.js:46:26)",
        "PipelineRenderer.renderElement (vscode/out/vs/base/browser/ui/list/listWidget.js:938:26)",
        "ListView.insertItemInDOM (vscode/out/vs/base/browser/ui/list/listView.js:636:23)",
        "ListView._splice (vscode/out/vs/base/browser/ui/list/listView.js:426:26)",
        "ListView.splice (vscode/out/vs/base/browser/ui/list/listView.js:344:29)",
        "vscode/out/vs/base/browser/ui/list/splice.js:14:45",
        "Array.forEach (<anonymous>)",
        "CombinedSpliceable.splice (vscode/out/vs/base/browser/ui/list/splice.js:14:30)",
        "vscode/out/vs/base/browser/ui/list/listWidget.js:1187:67",
        "EventBufferer.bufferEvents (vscode/out/vs/base/common/event.js:1233:23)",
        "List.splice (vscode/out/vs/base/browser/ui/list/listWidget.js:1187:32)",
        "WorkbenchTable.splice (vscode/out/vs/base/browser/ui/table/tableWidget.js:155:23)",
        "KeybindingsEditor.renderKeybindingsEntries (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:465:39)",
        "KeybindingsEditor.render (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:417:22)",
        "async EditorPanes.doSetInput (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:313:17)",
        "async EditorPanes.doOpenEditor (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:180:44)",
        "async EditorPanes.openEditor (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:78:28)",
        "async vscode/out/vs/workbench/browser/parts/editor/editorGroupView.js:846:65",
        "async PreferencesService.openGlobalKeybindingSettings (vscode/out/vs/workbench/services/preferences/browser/preferencesService.js:253:33)",
        "async Object.accept (vscode/out/vs/platform/quickinput/browser/commandsQuickAccess.js:211:31)"
      ],
      "count": 25,
      "originalStack": ["vscode/src/vs/base/browser/ui/actionbar/actionViewItems.ts:121:69"],
      "originalName": null
    },
    {
      "type": "contextmenu",
      "description": "(e) => {\n                        DOM.EventHelper.stop(e, true);\n                    }",
      "objectId": "7535147866608838792.4.14635",
      "stack": [
        "listener (vscode/out/vs/base/browser/ui/actionbar/actionbar.js:258:132)",
        "new DomListener (vscode/out/vs/base/browser/dom.js:87:24)",
        "Object.addDisposableListener (vscode/out/vs/base/browser/dom.js:101:16)",
        "vscode/out/vs/base/browser/ui/actionbar/actionbar.js:259:60",
        "Array.forEach (<anonymous>)",
        "ActionBar.push (vscode/out/vs/base/browser/ui/actionbar/actionbar.js:245:21)",
        "ActionsColumnRenderer.renderElement (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:722:36)",
        "TableListRenderer.renderElement (vscode/out/vs/base/browser/ui/table/tableWidget.js:46:26)",
        "PipelineRenderer.renderElement (vscode/out/vs/base/browser/ui/list/listWidget.js:938:26)",
        "ListView.insertItemInDOM (vscode/out/vs/base/browser/ui/list/listView.js:636:23)",
        "ListView._splice (vscode/out/vs/base/browser/ui/list/listView.js:426:26)",
        "ListView.splice (vscode/out/vs/base/browser/ui/list/listView.js:344:29)",
        "vscode/out/vs/base/browser/ui/list/splice.js:14:45",
        "Array.forEach (<anonymous>)",
        "CombinedSpliceable.splice (vscode/out/vs/base/browser/ui/list/splice.js:14:30)",
        "vscode/out/vs/base/browser/ui/list/listWidget.js:1187:67",
        "EventBufferer.bufferEvents (vscode/out/vs/base/common/event.js:1233:23)",
        "List.splice (vscode/out/vs/base/browser/ui/list/listWidget.js:1187:32)",
        "WorkbenchTable.splice (vscode/out/vs/base/browser/ui/table/tableWidget.js:155:23)",
        "KeybindingsEditor.renderKeybindingsEntries (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:465:39)",
        "KeybindingsEditor.render (vscode/out/vs/workbench/contrib/preferences/browser/keybindingsEditor.js:417:22)",
        "async EditorPanes.doSetInput (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:313:17)",
        "async EditorPanes.doOpenEditor (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:180:44)",
        "async EditorPanes.openEditor (vscode/out/vs/workbench/browser/parts/editor/editorPanes.js:78:28)",
        "async vscode/out/vs/workbench/browser/parts/editor/editorGroupView.js:846:65",
        "async PreferencesService.openGlobalKeybindingSettings (vscode/out/vs/workbench/services/preferences/browser/preferencesService.js:253:33)",
        "async Object.accept (vscode/out/vs/platform/quickinput/browser/commandsQuickAccess.js:211:31)"
      ],
      "count": 25,
      "originalStack": ["vscode/src/vs/base/browser/ui/actionbar/actionbar.ts:372:117"],
      "originalName": null
    }
  ]
}

Test script

git clone git@github.com:SimonSiefke/vscode-memory-leak-finder.git &&
cd vscode-memory-leak-finder &&
git checkout v5.36.0 &&
npm ci &&
node packages/cli/bin/test.js --cwd packages/e2e  --check-leaks --measure-after --measure event-listeners-with-stack-traces --runs 7  --only keybindings-editor.open &&
cat .vscode-memory-leak-finder-results/event-listeners-with-stack-traces/keybindings-editor.open.json

Additional Information

~The ActionBar in keyBindingsEditor.ts doesn't seem to be registered like other disposables:~

    renderTemplate(container: HTMLElement): IActionsColumnTemplateData {
        const element = DOM.append(container, $('.actions'));
        const actionBar = new ActionBar(element, { animated: false });
        return { actionBar };
    }

~Disposing the ActionBar could perhaps fix the memory leak / the leaking event listeners.~

Edit: The ActionBar is actually properly disposed 40 lines below in the disposeTemplate function.

ulugbekna commented 5 months ago

Thank for you the issue and proposed fix! Very much appreciated!