Skip to content

Fix cross-AppDomain TaskItem modifier cache regression#13493

Open
DustinCampbell wants to merge 1 commit intomainfrom
dev/dustinca/fix-cross-appdomain-taskitem-cache
Open

Fix cross-AppDomain TaskItem modifier cache regression#13493
DustinCampbell wants to merge 1 commit intomainfrom
dev/dustinca/fix-cross-appdomain-taskitem-cache

Conversation

@DustinCampbell
Copy link
Copy Markdown
Member

@DustinCampbell DustinCampbell commented Apr 6, 2026

The ItemSpecModifiers.Cache struct I introduced with #13386 caused a surprising ~200 MB allocation regression in Visual Studio scenarios on .NET Framework. Essentially, when TaskItem (a MarshalByRefObject) cached modifiers in an embedded struct, there's a huge cost to copy that struct cross-AppDomain.

To fix the problem, reduce the Cache struct to just a single field to store the full path. This should effectively bring memory allocations back in line.

Copilot AI review requested due to automatic review settings April 6, 2026 20:32
Copy link
Copy Markdown
Contributor

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

Fixes a .NET Framework Visual Studio allocation regression caused by copying an embedded modifier-cache struct across AppDomains by moving the cache onto the item objects themselves via an internal interface.

Changes:

  • Replace ItemSpecModifiers.Cache struct with an IItemSpecModifierCache interface and update modifier computation to use it.
  • Implement per-item modifier caching directly on TaskItem, ProjectItem, ProjectItemInstance.TaskItem, and TaskParameterTaskItem.
  • Refactor ItemSpecModifiers.GetItemSpecModifier into caching vs non-caching overloads and extract defining-project modifier resolution.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Utilities/TaskItem.cs Moves derivable modifier caching onto TaskItem via IItemSpecModifierCache and clears cache on ItemSpec changes.
src/Shared/TaskParameter.cs Updates TaskParameterTaskItem to use IItemSpecModifierCache for modifier caching.
src/Framework/ItemSpecModifiers.cs Reworks modifier computation to support caching through IItemSpecModifierCache and adds a non-caching overload.
src/Framework/IItemSpecModifierCache.cs Introduces internal interface for per-item derivable modifier caching across AppDomain boundaries.
src/Framework.UnitTests/FileUtilities_Tests.cs Updates tests to use the new cache interface instead of the removed struct cache.
src/Build/Instance/ProjectItemInstance.cs Implements cache interface on ProjectItemInstance.TaskItem, clears cache on spec changes, and copies cache on clone.
src/Build/Definition/ProjectItem.cs Implements cache interface on ProjectItem and routes built-in metadata through the new cache API.
src/Build/Definition/BuiltInMetadata.cs Switches built-in metadata APIs from ref Cache to IItemSpecModifierCache.

@JanProvaznik
Copy link
Copy Markdown
Member

JanProvaznik commented Apr 7, 2026

experimentally inserting to run speedometer at exp/dev/dustinca/fix-cross-appdomain-taskitem-cache branch (ETA results in 8h)
edit: oops you already did that when submitting pr and it was blocked on infra
https://devdiv.visualstudio.com/DevDiv/_git/VS/pullrequest/725889

Recently, ItemSpecModifiers.GetItemSpecModifier was changed to take a Cache struct rather than a single "string? fullPath" parameter. Unfortunately, this increases memory allocations to an unexpected degree -- especially in cross-AppDomain scenarios. This change reduces the size of the Cache struct to just a single FullPath field, which should remove the allocation regression.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants