From 1c967bb7c6acfc043c080a8abce251a5a605a61d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 5 Jun 2024 08:38:34 +0200 Subject: [PATCH] fix leaking listeners, track dispoable workbench contributions (#214301) * fix leaking listener https://github.com/microsoft/vscode/issues/214234 * track disposable workbench contribution and dispose them on shutdown fyi @bpasero https://github.com/microsoft/vscode/issues/214234 * fix leaking listener https://github.com/microsoft/vscode/issues/214234 --- src/vs/workbench/common/contributions.ts | 10 +++++++++- .../inlineChat/browser/inlineChatSessionServiceImpl.ts | 7 +++++-- .../services/decorations/browser/decorationsService.ts | 10 +++++----- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/common/contributions.ts b/src/vs/workbench/common/contributions.ts index aaf1452c25a..224c09e3bb1 100644 --- a/src/vs/workbench/common/contributions.ts +++ b/src/vs/workbench/common/contributions.ts @@ -11,7 +11,7 @@ import { mark } from 'vs/base/common/performance'; import { ILogService } from 'vs/platform/log/common/log'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { getOrSet } from 'vs/base/common/map'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore, isDisposable } from 'vs/base/common/lifecycle'; import { IEditorPaneService } from 'vs/workbench/services/editor/common/editorPaneService'; /** @@ -156,6 +156,7 @@ export class WorkbenchContributionsRegistry extends Disposable implements IWorkb private readonly contributionsById = new Map(); private readonly instancesById = new Map(); + private readonly instanceDisposables = this._register(new DisposableStore()); private readonly timingsByPhase = new Map>(); get timings() { return this.timingsByPhase; } @@ -249,6 +250,10 @@ export class WorkbenchContributionsRegistry extends Disposable implements IWorkb const environmentService = this.environmentService = accessor.get(IEnvironmentService); const editorPaneService = this.editorPaneService = accessor.get(IEditorPaneService); + this._register(lifecycleService.onWillShutdown(() => { + this.instanceDisposables.clear(); + })); + // Instantiate contributions by phase when they are ready for (const phase of [LifecyclePhase.Starting, LifecyclePhase.Ready, LifecyclePhase.Restored, LifecyclePhase.Eventually]) { this.instantiateByPhase(instantiationService, lifecycleService, logService, environmentService, phase); @@ -377,6 +382,9 @@ export class WorkbenchContributionsRegistry extends Disposable implements IWorkb this.instancesById.set(contribution.id, instance); this.contributionsById.delete(contribution.id); } + if (isDisposable(instance)) { + this.instanceDisposables.add(instance); + } } catch (error) { logService.error(`Unable to create workbench contribution '${contribution.id ?? contribution.ctor.name}'.`, error); } finally { diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts index e7c39a315ef..e77461a562c 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts @@ -383,18 +383,21 @@ export class InlineChatEnabler { private readonly _ctxHasProvider: IContextKey; + private readonly _store = new DisposableStore(); + constructor( @IContextKeyService contextKeyService: IContextKeyService, @IChatAgentService chatAgentService: IChatAgentService ) { this._ctxHasProvider = CTX_INLINE_CHAT_HAS_AGENT.bindTo(contextKeyService); - chatAgentService.onDidChangeAgents(() => { + this._store.add(chatAgentService.onDidChangeAgents(() => { const hasEditorAgent = Boolean(chatAgentService.getDefaultAgent(ChatAgentLocation.Editor)); this._ctxHasProvider.set(hasEditorAgent); - }); + })); } dispose() { this._ctxHasProvider.reset(); + this._store.dispose(); } } diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index edf7fb27300..7453c76c816 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -245,8 +245,9 @@ export class DecorationsService implements IDecorationsService { declare _serviceBrand: undefined; - private readonly _onDidChangeDecorationsDelayed = new DebounceEmitter({ merge: all => all.flat() }); - private readonly _onDidChangeDecorations = new Emitter(); + private readonly _store = new DisposableStore(); + private readonly _onDidChangeDecorationsDelayed = this._store.add(new DebounceEmitter({ merge: all => all.flat() })); + private readonly _onDidChangeDecorations = this._store.add(new Emitter()); onDidChangeDecorations: Event = this._onDidChangeDecorations.event; @@ -261,12 +262,11 @@ export class DecorationsService implements IDecorationsService { this._decorationStyles = new DecorationStyles(themeService); this._data = TernarySearchTree.forUris(key => uriIdentityService.extUri.ignorePathCasing(key)); - this._onDidChangeDecorationsDelayed.event(event => { this._onDidChangeDecorations.fire(new FileDecorationChangeEvent(event)); }); + this._store.add(this._onDidChangeDecorationsDelayed.event(event => { this._onDidChangeDecorations.fire(new FileDecorationChangeEvent(event)); })); } dispose(): void { - this._onDidChangeDecorations.dispose(); - this._onDidChangeDecorationsDelayed.dispose(); + this._store.dispose(); this._data.clear(); }