Description
We've recently encountered a method allocating even though there was no allocate-y code running. We've since tracked this down to the following:
IL shows the capturing lambda's DisplayClass always seems to be "allocated" as soon as the method is entered, but the JIT has the ability to control when the object is initialised. When the lambda captures both a local and this, the JIT is suddenly unable to forego this initialisation even if the method terminates execution early.
Here's a gist that shows the issue: https://gist.github.com/smoogipoo/810c033962b8a95289dbdabd9d84801b
And a SharpLab repro.
Is this a valid and/or known issue, or something we should be wary of going forward?
Configuration + Data
BenchmarkDotNet=v0.12.1, OS=manjaro
AMD Ryzen 9 3950X, 1 CPU, 32 logical and 16 physical cores
.NET Core SDK=3.1.103
[Host] : .NET Core 2.2.8 (CoreCLR 4.6.28207.03, CoreFX 4.6.28208.02), X64 RyuJIT
.NET Core 2.2 : .NET Core 2.2.8 (CoreCLR 4.6.28207.03, CoreFX 4.6.28208.02), X64 RyuJIT
.NET Core 3.1 : .NET Core 3.1.3 (CoreCLR 4.700.20.11803, CoreFX 4.700.20.12001), X64 RyuJIT
| Method |
Job |
Runtime |
Mean |
Error |
StdDev |
Ratio |
RatioSD |
Gen 0 |
Gen 1 |
Gen 2 |
Allocated |
| SafeMethod |
.NET Core 2.2 |
.NET Core 2.2 |
545.8 ns |
0.47 ns |
0.41 ns |
1.00 |
0.00 |
- |
- |
- |
- |
| AllocatingMethod |
.NET Core 2.2 |
.NET Core 2.2 |
7,151.4 ns |
135.02 ns |
112.75 ns |
13.10 |
0.20 |
24.4064 |
- |
- |
32000 B |
|
|
|
|
|
|
|
|
|
|
|
|
| SafeMethod |
.NET Core 3.1 |
.NET Core 3.1 |
276.8 ns |
0.26 ns |
0.23 ns |
1.00 |
0.00 |
- |
- |
- |
- |
| AllocatingMethod |
.NET Core 3.1 |
.NET Core 3.1 |
9,072.8 ns |
179.96 ns |
438.05 ns |
32.64 |
1.40 |
0.9460 |
- |
- |
32000 B |
I've also run this on mono, which seems to always initialise the object (see Gen 0, Benchmark.Net doesn't seem to have allocation tracking on mono).
BenchmarkDotNet=v0.12.1, OS=manjaro
AMD Ryzen 9 3950X, 1 CPU, 32 logical and 16 physical cores
[Host] : Mono 6.4.0 (makepkg/fe64a4765e6 Sat), X64
Job-CKTNGU : Mono 6.4.0 (makepkg/fe64a4765e6 Sat), X64
Runtime=Mono
| Method |
Mean |
Error |
StdDev |
Ratio |
Gen 0 |
Gen 1 |
Gen 2 |
Allocated |
| SafeMethod |
4.491 us |
0.0069 us |
0.0054 us |
1.00 |
5.7449 |
- |
- |
- |
| AllocatingMethod |
5.031 us |
0.0076 us |
0.0064 us |
1.12 |
7.6904 |
- |
- |
- |
category:cq
theme:dead-code
skill-level:expert
cost:medium
Description
We've recently encountered a method allocating even though there was no allocate-y code running. We've since tracked this down to the following:
IL shows the capturing lambda's
DisplayClassalways seems to be "allocated" as soon as the method is entered, but the JIT has the ability to control when the object is initialised. When the lambda captures both a local andthis, the JIT is suddenly unable to forego this initialisation even if the method terminates execution early.Here's a gist that shows the issue: https://gist.github.com/smoogipoo/810c033962b8a95289dbdabd9d84801b
And a SharpLab repro.
Is this a valid and/or known issue, or something we should be wary of going forward?
Configuration + Data
I've also run this on mono, which seems to always initialise the object (see
Gen 0, Benchmark.Net doesn't seem to have allocation tracking on mono).category:cq
theme:dead-code
skill-level:expert
cost:medium