Skip to content

Fix: Prevent memory leak in view model lifecycle #40216

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

tanchekwei
Copy link
Contributor

@tanchekwei tanchekwei commented Jun 24, 2025

Summary of the Pull Request

A memory leak was identified where activating a Command Palette extension via a hotkey would lead to a linear increase in resource consumption and a corresponding decrease in search performance.

Each activation created a new PageViewModel instance for the extension's UI. However, the ShellViewModel did not dispose of the previous PageViewModel instance when a new one was created.

The fix is implemented in Microsoft.CmdPal.UI.ViewModels/ShellViewModel.cs by ensuring that PageViewModel instances are correctly disposed of when they are no longer active.

PR Checklist

Validation Steps Performed

  1. Installed Workspace Launcher for Visual Studio / Code
  2. Configured a global hotkey for the extension (e.g., Alt + Q).
  3. Ran the following AHK script. Pressing F1 simulates pressing the hotkey 10 times with a 200ms interval, followed by typing p to trigger a search and observe how many times GetItems is invoked.
#NoEnv
SetBatchLines, -1

; Press F1 to run the sequence
F1::
Loop, 10
{
    Send, !q
    Sleep, 200
}
Send, p
return

Before the Fix (PowerToys v0.91.1)

  • Pressing the hotkey 10 times then search will triggered GetItems 12 times.
  • See video and log output below:
2025-06-25.00-04-55.mp4
[2025-06-25 00:04:58.251] [VisualStudioCodePage.UpdateSearchText] Started
[2025-06-25 00:04:58.251] [VisualStudioCodePage.UpdateSearchText] SearchText: p
[2025-06-25 00:04:58.251] [WorkspaceFilter.Filter] Started
[2025-06-25 00:04:58.263] [WorkspaceFilter.Filter] Finished in 11ms
[2025-06-25 00:04:58.269] [VisualStudioCodePage.GetItems] Started
[2025-06-25 00:04:58.269] [VisualStudioCodePage.GetItems] Finished in 0ms
[2025-06-25 00:04:58.373] [VisualStudioCodePage.GetItems] Started
[2025-06-25 00:04:58.373] [VisualStudioCodePage.GetItems] Finished in 0ms
[2025-06-25 00:04:58.408] [VisualStudioCodePage.GetItems] Started
[2025-06-25 00:04:58.408] [VisualStudioCodePage.GetItems] Finished in 0ms
[2025-06-25 00:04:58.445] [VisualStudioCodePage.GetItems] Started
[2025-06-25 00:04:58.446] [VisualStudioCodePage.GetItems] Finished in 0ms
[2025-06-25 00:04:58.485] [VisualStudioCodePage.GetItems] Started
[2025-06-25 00:04:58.486] [VisualStudioCodePage.GetItems] Finished in 0ms
[2025-06-25 00:04:58.524] [VisualStudioCodePage.GetItems] Started
[2025-06-25 00:04:58.525] [VisualStudioCodePage.GetItems] Finished in 0ms
[2025-06-25 00:04:58.563] [VisualStudioCodePage.GetItems] Started
[2025-06-25 00:04:58.564] [VisualStudioCodePage.GetItems] Finished in 0ms
[2025-06-25 00:04:58.604] [VisualStudioCodePage.GetItems] Started
[2025-06-25 00:04:58.604] [VisualStudioCodePage.GetItems] Finished in 0ms
[2025-06-25 00:04:58.645] [VisualStudioCodePage.GetItems] Started
[2025-06-25 00:04:58.645] [VisualStudioCodePage.GetItems] Finished in 0ms
[2025-06-25 00:04:58.685] [VisualStudioCodePage.GetItems] Started
[2025-06-25 00:04:58.686] [VisualStudioCodePage.GetItems] Finished in 0ms
[2025-06-25 00:04:58.755] [VisualStudioCodePage.GetItems] Started
[2025-06-25 00:04:58.756] [VisualStudioCodePage.GetItems] Finished in 0ms
[2025-06-25 00:04:58.798] [VisualStudioCodePage.GetItems] Started
[2025-06-25 00:04:58.798] [VisualStudioCodePage.GetItems] Finished in 0ms
[2025-06-25 00:04:58.843] [VisualStudioCodePage.UpdateSearchText] Finished in 591ms

After the Fix

  • Pressing the hotkey 10 times then search will now triggers GetItems only once.
  • See updated video and log output:
after.fix.mp4

[2025-06-25 00:03:44.862] [VisualStudioCodePage.UpdateSearchText] Started
[2025-06-25 00:03:44.863] [VisualStudioCodePage.UpdateSearchText] SearchText: p
[2025-06-25 00:03:44.864] [WorkspaceFilter.Filter] Started
[2025-06-25 00:03:44.866] [WorkspaceFilter.Filter] Finished in 2ms
[2025-06-25 00:03:44.870] [VisualStudioCodePage.GetItems] Started
[2025-06-25 00:03:44.870] [VisualStudioCodePage.GetItems] Finished in 0ms
[2025-06-25 00:03:44.909] [VisualStudioCodePage.UpdateSearchText] Finished in 46ms

@michaeljolley michaeljolley requested a review from Copilot June 26, 2025 04:02
@michaeljolley michaeljolley added the Product-Command Palette Refers to the Command Palette utility label Jun 26, 2025
@michaeljolley
Copy link
Contributor

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes a memory leak by disposing previous PageViewModel instances when CurrentPage is updated in ShellViewModel.

  • Converted CurrentPage from an auto-generated observable property to a manual property with disposal logic
  • Removed the [ObservableProperty] attribute on CurrentPage
  • Added a backing field _currentPage and custom setter to dispose old pages
Comments suppressed due to low confidence (2)

src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/ShellViewModel.cs:34

  • [nitpick] Add XML documentation to the CurrentPage property to note that assigning a new page will dispose of the previous instance.
    public PageViewModel CurrentPage

src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/ShellViewModel.cs:42

  • Consider adding a unit test to verify that when CurrentPage is updated, the previous PageViewModel is properly disposed.
                if (oldValue is IDisposable disposable)

Copy link
Contributor

@michaeljolley michaeljolley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@michaeljolley
Copy link
Contributor

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@tanchekwei
Copy link
Contributor Author

The Win32ProgramRepositoryMustCallOnAppRenamedForLnkAppsWhenRenamedEventIsRaised test case passed successfully on my end.

image

@tanchekwei tanchekwei requested a review from michaeljolley June 27, 2025 01:21
@michaeljolley
Copy link
Contributor

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Product-Command Palette Refers to the Command Palette utility
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants