Skip to content

fix: memory leak in settings widget #221518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 12, 2024

Conversation

SimonSiefke
Copy link
Contributor

Fixes a memory leak in the settings widget: In this case, it seems the buttons should be registered to listDisposables instead of using this._register.

Event listeners (before)

When adding and removing a property using the settings editor 97 times, the number of event listeners increases by 112 or 88:

{
  "eventListenersWithStackTrace": [
    {
      "type": "-monaco-gesturetap",
      "description": "(e)=>{\n                    if (!this.enabled) {\n                        _dom.EventHelper.stop(e);\n                        return;\n                    }\n                    this._onDidClick.fire(e);\n                }",
      "objectId": "248964314466703071.4.25757",
      "sourceMaps": [""],
      "stack": [
        "listener (vscode/out/vs/base/browser/ui/button/button.js:102:89)",
        "new DomListener (vscode/out/vs/base/browser/dom.js:516:24)",
        "addDisposableListener (vscode/out/vs/base/browser/dom.js:528:16)",
        "vscode/out/vs/base/browser/ui/button/button.js:103:63",
        "Array.forEach (<anonymous>)",
        "new Button (vscode/out/vs/base/browser/ui/button/button.js:102:15)",
        "ObjectSettingDropdownWidget.renderEdit (vscode/out/vs/workbench/contrib/preferences/browser/settingsWidgets.js:902:49)",
        "ObjectSettingDropdownWidget.renderDataOrEditItem (vscode/out/vs/workbench/contrib/preferences/browser/settingsWidgets.js:278:52)",
        "vscode/out/vs/workbench/contrib/preferences/browser/settingsWidgets.js:231:69",
        "Array.map (<anonymous>)",
        "ObjectSettingDropdownWidget.renderList (vscode/out/vs/workbench/contrib/preferences/browser/settingsWidgets.js:231:49)",
        "UniqueContainer.value (vscode/out/vs/workbench/contrib/preferences/browser/settingsWidgets.js:310:22)",
        "Emitter._deliver (vscode/out/vs/base/common/event.js:790:26)",
        "Emitter.fire (vscode/out/vs/base/common/event.js:809:22)",
        "HTMLAnchorElement.<anonymous> (vscode/out/vs/base/browser/ui/button/button.js:108:38)"
      ],
      "count": 112
    },
    {
      "type": "-monaco-gesturetap",
      "description": "(e)=>{\n                    if (!this.enabled) {\n                        _dom.EventHelper.stop(e);\n                        return;\n                    }\n                    this._onDidClick.fire(e);\n                }",
      "objectId": "248964314466703071.4.25775",
      "sourceMaps": [""],
      "stack": [
        "listener (vscode/out/vs/base/browser/ui/button/button.js:102:89)",
        "new DomListener (vscode/out/vs/base/browser/dom.js:516:24)",
        "addDisposableListener (vscode/out/vs/base/browser/dom.js:528:16)",
        "vscode/out/vs/base/browser/ui/button/button.js:103:63",
        "Array.forEach (<anonymous>)",
        "new Button (vscode/out/vs/base/browser/ui/button/button.js:102:15)",
        "ObjectSettingDropdownWidget.renderEdit (vscode/out/vs/workbench/contrib/preferences/browser/settingsWidgets.js:897:45)",
        "ObjectSettingDropdownWidget.renderDataOrEditItem (vscode/out/vs/workbench/contrib/preferences/browser/settingsWidgets.js:278:52)",
        "vscode/out/vs/workbench/contrib/preferences/browser/settingsWidgets.js:231:69",
        "Array.map (<anonymous>)",
        "ObjectSettingDropdownWidget.renderList (vscode/out/vs/workbench/contrib/preferences/browser/settingsWidgets.js:231:49)",
        "UniqueContainer.value (vscode/out/vs/workbench/contrib/preferences/browser/settingsWidgets.js:310:22)",
        "Emitter._deliver (vscode/out/vs/base/common/event.js:790:26)",
        "Emitter.fire (vscode/out/vs/base/common/event.js:809:22)",
        "HTMLAnchorElement.<anonymous> (vscode/out/vs/base/browser/ui/button/button.js:108:38)"
      ],
      "count": 112
    },
    {
      "type": "-monaco-gesturetap",
      "description": "(e)=>{\n                    if (!this.enabled) {\n                        _dom.EventHelper.stop(e);\n                        return;\n                    }\n                    this._onDidClick.fire(e);\n                }",
      "objectId": "248964314466703071.4.24537",
      "sourceMaps": [""],
      "stack": [
        "listener (vscode/out/vs/base/browser/ui/button/button.js:102:89)",
        "DomListener (vscode/out/vs/base/browser/dom.js:516:24)",
        "addDisposableListener (vscode/out/vs/base/browser/dom.js:528:16)",
        "vscode/out/vs/base/browser/ui/button/button.js:103:63",
        "Array.forEach (<anonymous>)",
        "new Button (vscode/out/vs/base/browser/ui/button/button.js:102:15)",
        "ObjectSettingDropdownWidget.renderEdit (vscode/out/vs/workbench/contrib/preferences/browser/settingsWidgets.js:897:45)",
        "ObjectSettingDropdownWidget.renderDataOrEditItem (vscode/out/vs/workbench/contrib/preferences/browser/settingsWidgets.js:278:52)",
        "vscode/out/vs/workbench/contrib/preferences/browser/settingsWidgets.js:231:69",
        "Array.map (<anonymous>)",
        "ObjectSettingDropdownWidget.renderList (vscode/out/vs/workbench/contrib/preferences/browser/settingsWidgets.js:231:49)",
        "UniqueContainer.value (vscode/out/vs/workbench/contrib/preferences/browser/settingsWidgets.js:310:22)",
        "Emitter._deliver (vscode/out/vs/base/common/event.js:790:26)",
        "Emitter.fire (vscode/out/vs/base/common/event.js:809:22)",
        "HTMLAnchorElement.<anonymous> (vscode/out/vs/base/browser/ui/button/button.js:108:38)"
      ],
      "count": 82
    }
  ]
}

Event listeners (after)

The number of event listeners stays basically constant:

{
  "eventListenersWithStackTrace": [
    {
      "type": "focus",
      "description": "()=>{\n                if (isMouseDown || hoverPreparation) {\n                    return;\n                }\n                const target = {\n                    targetElements: [\n                        targetElement\n                    ],\n                    dispose: ()=>{}\n                };\n                const toDispose = new _lifecycle.DisposableStore();\n                const onBlur = ()=>hideHover(true, true);\n                toDispose.add((0, _dom.addDisposableListener)(targetElement, _dom.EventType.BLUR, onBlur, true));\n                toDispose.add(triggerShowHover(hoverDelegate.delay, false, target));\n                hoverPreparation = toDispose;\n            }",
      "objectId": "7375899917376070588.4.18654",
      "sourceMaps": [""],
      "stack": [
        "listener (vscode/out/vs/editor/browser/services/hoverService/hoverService.js:250:28)",
        "new DomListener (vscode/out/vs/base/browser/dom.js:516:24)",
        "addDisposableListener (vscode/out/vs/base/browser/dom.js:528:16)",
        "HoverService.setupManagedHover (vscode/out/vs/editor/browser/services/hoverService/hoverService.js:270:66)",
        "SettingObjectRenderer.renderSettingElement (vscode/out/vs/workbench/contrib/preferences/browser/settingsTree.js:852:64)",
        "SettingObjectRenderer.renderElement (vscode/out/vs/workbench/contrib/preferences/browser/settingsTree.js:1194:19)",
        "TreeRenderer.renderElement (vscode/out/vs/base/browser/ui/tree/abstractTree.js:379:27)",
        "PipelineRenderer.renderElement (vscode/out/vs/base/browser/ui/list/listWidget.js:1028:26)",
        "ListView.insertItemInDOM (vscode/out/vs/base/browser/ui/list/listView.js:705:23)",
        "ListView._splice (vscode/out/vs/base/browser/ui/list/listView.js:495:26)",
        "ListView.splice (vscode/out/vs/base/browser/ui/list/listView.js:404:29)",
        "vscode/out/vs/base/browser/ui/list/splice.js:20:45",
        "Array.forEach (<anonymous>)",
        "CombinedSpliceable.splice (vscode/out/vs/base/browser/ui/list/splice.js:20:30)",
        "vscode/out/vs/base/browser/ui/list/listWidget.js:1312:65",
        "EventBufferer.bufferEvents (vscode/out/vs/base/common/event.js:1071:23)",
        "TreeNodeList.splice (vscode/out/vs/base/browser/ui/list/listWidget.js:1312:32)",
        "TreeNodeList.splice (vscode/out/vs/base/browser/ui/tree/abstractTree.js:1891:19)",
        "IndexTreeModel.rerender (vscode/out/vs/base/browser/ui/tree/indexTreeModel.js:217:27)",
        "NonCollapsibleObjectTreeModel.rerender (vscode/out/vs/base/browser/ui/tree/objectTreeModel.js:136:24)",
        "SettingsTree.rerender (vscode/out/vs/base/browser/ui/tree/objectTree.js:50:24)",
        "SettingsEditor2.refreshSingleElement (vscode/out/vs/workbench/contrib/preferences/browser/settingsEditor2.js:1277:35)",
        "SettingsEditor2.renderTree (vscode/out/vs/workbench/contrib/preferences/browser/settingsEditor2.js:1263:26)",
        "vscode/out/vs/workbench/contrib/preferences/browser/settingsEditor2.js:985:22"
      ],
      "count": 1
    },
    {
      "type": "mouseover",
      "description": "(e)=>{\n                if (hoverPreparation) {\n                    return;\n                }\n                const toDispose = new _lifecycle.DisposableStore();\n                const target = {\n                    targetElements: [\n                        targetElement\n                    ],\n                    dispose: ()=>{}\n                };\n                if (hoverDelegate.placement === undefined || hoverDelegate.placement === 'mouse') {\n                    const onMouseMove = (e)=>{\n                        target.x = e.x + 10;\n                        if ((0, _dom.isHTMLElement)(e.target) && getHoverTargetElement(e.target, targetElement) !== targetElement) {\n                            hideHover(true, true);\n                        }\n                    };\n                    toDispose.add((0, _dom.addDisposableListener)(targetElement, _dom.EventType.MOUSE_MOVE, onMouseMove, true));\n                }\n                hoverPreparation = toDispose;\n                if ((0, _dom.isHTMLElement)(e.target) && getHoverTargetElement(e.target, targetElement) !== targetElement) {\n                    return;\n                }\n                toDispose.add(triggerShowHover(hoverDelegate.delay, false, target));\n            }",
      "objectId": "7375899917376070588.4.18652",
      "sourceMaps": [""],
      "stack": [
        "listener (vscode/out/vs/editor/browser/services/hoverService/hoverService.js:223:32)",
        "new DomListener (vscode/out/vs/base/browser/dom.js:516:24)",
        "addDisposableListener (vscode/out/vs/base/browser/dom.js:528:16)",
        "HoverService.setupManagedHover (vscode/out/vs/editor/browser/services/hoverService/hoverService.js:250:72)",
        "SettingObjectRenderer.renderSettingElement (vscode/out/vs/workbench/contrib/preferences/browser/settingsTree.js:852:64)",
        "SettingObjectRenderer.renderElement (vscode/out/vs/workbench/contrib/preferences/browser/settingsTree.js:1194:19)",
        "TreeRenderer.renderElement (vscode/out/vs/base/browser/ui/tree/abstractTree.js:379:27)",
        "PipelineRenderer.renderElement (vscode/out/vs/base/browser/ui/list/listWidget.js:1028:26)",
        "ListView.insertItemInDOM (vscode/out/vs/base/browser/ui/list/listView.js:705:23)",
        "ListView._splice (vscode/out/vs/base/browser/ui/list/listView.js:495:26)",
        "ListView.splice (vscode/out/vs/base/browser/ui/list/listView.js:404:29)",
        "vscode/out/vs/base/browser/ui/list/splice.js:20:45",
        "Array.forEach (<anonymous>)",
        "CombinedSpliceable.splice (vscode/out/vs/base/browser/ui/list/splice.js:20:30)",
        "vscode/out/vs/base/browser/ui/list/listWidget.js:1312:65",
        "EventBufferer.bufferEvents (vscode/out/vs/base/common/event.js:1071:23)",
        "TreeNodeList.splice (vscode/out/vs/base/browser/ui/list/listWidget.js:1312:32)",
        "TreeNodeList.splice (vscode/out/vs/base/browser/ui/tree/abstractTree.js:1891:19)",
        "IndexTreeModel.rerender (vscode/out/vs/base/browser/ui/tree/indexTreeModel.js:217:27)",
        "NonCollapsibleObjectTreeModel.rerender (vscode/out/vs/base/browser/ui/tree/objectTreeModel.js:136:24)",
        "SettingsTree.rerender (vscode/out/vs/base/browser/ui/tree/objectTree.js:50:24)",
        "SettingsEditor2.refreshSingleElement (vscode/out/vs/workbench/contrib/preferences/browser/settingsEditor2.js:1277:35)",
        "SettingsEditor2.renderTree (vscode/out/vs/workbench/contrib/preferences/browser/settingsEditor2.js:1263:26)",
        "vscode/out/vs/workbench/contrib/preferences/browser/settingsEditor2.js:985:22"
      ],
      "count": 1
    },
    {
      "type": "mouseleave",
      "description": "(e)=>{\n                isMouseDown = false;\n                hideHover(false, e.fromElement === targetElement);\n            }",
      "objectId": "7375899917376070588.4.18650",
      "sourceMaps": [""],
      "stack": [
        "listener (vscode/out/vs/editor/browser/services/hoverService/hoverService.js:219:113)",
        "new DomListener (vscode/out/vs/base/browser/dom.js:516:24)",
        "addDisposableListener (vscode/out/vs/base/browser/dom.js:528:16)",
        "HoverService.setupManagedHover (vscode/out/vs/editor/browser/services/hoverService/hoverService.js:220:70)",
        "SettingObjectRenderer.renderSettingElement (vscode/out/vs/workbench/contrib/preferences/browser/settingsTree.js:852:64)",
        "SettingObjectRenderer.renderElement (vscode/out/vs/workbench/contrib/preferences/browser/settingsTree.js:1194:19)",
        "TreeRenderer.renderElement (vscode/out/vs/base/browser/ui/tree/abstractTree.js:379:27)",
        "PipelineRenderer.renderElement (vscode/out/vs/base/browser/ui/list/listWidget.js:1028:26)",
        "ListView.insertItemInDOM (vscode/out/vs/base/browser/ui/list/listView.js:705:23)",
        "ListView._splice (vscode/out/vs/base/browser/ui/list/listView.js:495:26)",
        "ListView.splice (vscode/out/vs/base/browser/ui/list/listView.js:404:29)",
        "vscode/out/vs/base/browser/ui/list/splice.js:20:45",
        "Array.forEach (<anonymous>)",
        "CombinedSpliceable.splice (vscode/out/vs/base/browser/ui/list/splice.js:20:30)",
        "vscode/out/vs/base/browser/ui/list/listWidget.js:1312:65",
        "EventBufferer.bufferEvents (vscode/out/vs/base/common/event.js:1071:23)",
        "TreeNodeList.splice (vscode/out/vs/base/browser/ui/list/listWidget.js:1312:32)",
        "TreeNodeList.splice (vscode/out/vs/base/browser/ui/tree/abstractTree.js:1891:19)",
        "IndexTreeModel.rerender (vscode/out/vs/base/browser/ui/tree/indexTreeModel.js:217:27)",
        "NonCollapsibleObjectTreeModel.rerender (vscode/out/vs/base/browser/ui/tree/objectTreeModel.js:136:24)",
        "SettingsTree.rerender (vscode/out/vs/base/browser/ui/tree/objectTree.js:50:24)",
        "SettingsEditor2.refreshSingleElement (vscode/out/vs/workbench/contrib/preferences/browser/settingsEditor2.js:1277:35)",
        "SettingsEditor2.renderTree (vscode/out/vs/workbench/contrib/preferences/browser/settingsEditor2.js:1263:26)",
        "vscode/out/vs/workbench/contrib/preferences/browser/settingsEditor2.js:985:22"
      ],
      "count": 1
    }
  ]
}

@vscodenpa vscodenpa added this to the July 2024 milestone Jul 12, 2024
@rzhao271 rzhao271 enabled auto-merge (squash) July 12, 2024 16:50
@rzhao271 rzhao271 merged commit a0599a9 into microsoft:main Jul 12, 2024
6 checks passed
@vs-code-engineering vs-code-engineering bot locked and limited conversation to collaborators Aug 26, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants