Avoid in-process captures in UpdateReferencesAync#36161
Avoid in-process captures in UpdateReferencesAync#36161sharwell merged 1 commit intodotnet:masterfrom
Conversation
This change produced a 220MB (6.7%) allocation reduction in the scenario described by dotnet#36158.
a586bb4 to
2ec12e3
Compare
| } | ||
|
|
||
| private Task GetTask(Project project, Func<Task> func, CancellationToken cancellationToken) | ||
| [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/36158", AllowCaptures = false, Constraint = "Avoid captures to reduce GC pressure when running in the host workspace.")] |
There was a problem hiding this comment.
Shouldn't the attribute be applied to UpdateSymbolTreeInfoAsync above?
There was a problem hiding this comment.
➡️ No. UpdateSymbolTreeInfoAsync was not a significant source of allocations in the test scenario. The changes to the method are a side effect of the signature change, as opposed to a change directly intended to reduce allocations.
| ? GetNewTask(this, func, project, reference, cancellationToken) | ||
| : func(this, project, reference, cancellationToken); | ||
|
|
||
| static Task GetNewTask(IncrementalAnalyzer self, Func<IncrementalAnalyzer, Project, PortableExecutableReference, CancellationToken, Task> func, Project project, PortableExecutableReference reference, CancellationToken cancellationToken) |
There was a problem hiding this comment.
How does this help reduce allocation?
There was a problem hiding this comment.
➡️ If a method contains a lambda that captures parameters, a closure instance is created for those parameters at the start of the method whether or not the lambda is created or used. By moving the creation of the lambda to a local function, the creation of the closure instance is deferred until such time as the lambda actually needs to be created. This leaves the path above that doesn't use the lambda as a non-allocating code path.
This change produced a 220MB (6.7%) allocation reduction in the scenario described by #36158.