BenchmarkDotNet freezes when running multiple benchmark classes on .NET 10 (works fine on .NET 8)
BenchmarkDotNet freezes when running multiple benchmark classes on .NET 10 (works fine on .NET 8)
Description
After migrating my benchmark test suite to .NET 10, the benchmark run intermittently freezes mid-execution. The exact same suite works fine on .NET 8. This has been happening for months and I haven’t identified the cause.
Observed Behavior
- Usually occurs when running multiple benchmark classes, especially ones testing collections.
- No exception is thrown — the run just freezes and nothing new is logged.
- The .NET host process does not terminate after closing the console window.
- CPU usage continues to fluctuate.
- The benchmark output folder can’t be deleted until I kill the process (or reboot).
- Occasionally, I need a full reboot to clear it.
- Running one benchmark class at a time typically succeeds.
Expected Behavior
All benchmark classes should run sequentially and the process should exit normally with a summary, logs, and unlocked files.
Actual Behavior
When multiple benchmark classes run back-to-back, the process sometimes freezes indefinitely with no error output, leaving a lingering .NET host process and locked files.
Suspected Cause
Something may not be released/cleaned up when BenchmarkDotNet starts a new benchmark class, particularly in collection-focused benchmarks.
Reproduction Steps
- Configure a BenchmarkDotNet job targeting .NET 10.
- Run two or more benchmark classes sequentially in the same process.
- Observe that execution sometimes freezes after one class completes.
Configuration Snippet
var config = DefaultConfig.Instance
.AddJob(Job.Default.WithRuntime(CoreRuntime.Core10_0))
.WithSummaryStyle(SummaryStyle.Default.WithTimeUnit(BenchmarkDotNet.Horology.TimeUnit.Nanosecond));
_ = config.WithOption(ConfigOptions.DisableOptimizationsValidator, true);
// Running multiple classes back-to-back
_ = BenchmarkRunner.Run<CollectionCreatingBenchmark>(config);
_ = BenchmarkRunner.Run<CollectionCreatingLoopBenchmark>(config);
Environment
- BenchmarkDotNet version: 0.15.2
- .NET SDK version(s): 10.0.100-preview.7.25380.108
- .NET runtimes tested:
- .NET 8 (✅ works fine)
- .NET 10 (❌ freezes)
- OS: Windows 10 Pro 19045.6216
- CPU: Intel(R) Core(TM) i5-10400 CPU @ 2.90GHz 2.90 GHz
- RAM: 32 GB
Frequency / Scope
- Frequency: intermittent but frequent under load or when running multiple collection-related classes.
- Scope: only repros on .NET 10; .NET 8 is stable with identical code.
Workarounds Tried
- Running benchmarks one class at a time → usually succeeds.
- No exceptions observed; nothing meaningful added to logs.
Attachments
- Log from the last frozen run
- Project files showing configuration
Prior Contact
I spoke with someone on the .NET team; they hadn’t seen this before. Posting here first before escalating.
Questions
- Has anyone seen this behavior before?
- Would a minimal repro repo help? I can provide one.
- Any additional logging/diagnosers you’d like enabled on my side?
Thanks!
Project Setup
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AnalysisLevel>preview</AnalysisLevel>
<AssemblyVersion>2021.6.4.33120</AssemblyVersion>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Configurations>Release</Configurations>
<DebugSymbols>true</DebugSymbols>
<DebugType>none</DebugType>
<Description>Benchmarking source for the book.</Description>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<FileVersion>2022.6.4.33120</FileVersion>
<GarbageCollectionAdaptationMode>1</GarbageCollectionAdaptationMode>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<ImplicitUsings>enable</ImplicitUsings>
<IsPublishable>False</IsPublishable>
<LangVersion>preview</LangVersion>
<NeutralLanguage>en</NeutralLanguage>
<Nullable>enable</Nullable>
<NullableContextOptions>enable</NullableContextOptions>
<OldToolsVersion>2.0</OldToolsVersion>
<OutputType>Exe</OutputType>
<Platforms>AnyCPU</Platforms>
<PlatformTarget>AnyCPU</PlatformTarget>
<ServerGarbageCollection>true</ServerGarbageCollection>
<SignAssembly>False</SignAssembly>
<StartupObject>dotNetTips.CodePerf.Example.App.Program</StartupObject>
<TieredPGO>true</TieredPGO>
<TargetFramework>net10.0</TargetFramework>
<RunAnalyzersDuringBuild>False</RunAnalyzersDuringBuild>
<RunAnalyzersDuringLiveAnalysis>False</RunAnalyzersDuringLiveAnalysis>
<EnableNETAnalyzers>False</EnableNETAnalyzers>
<GenerateDocumentationFile>False</GenerateDocumentationFile>
<RunPostBuildEvent>Always</RunPostBuildEvent>
<ProduceReferenceAssembly>False</ProduceReferenceAssembly>
</PropertyGroup>
dotNetTips.CodePerf.Example.App.BenchmarkTests.CollectionCreatingLoopBenchmark-20250820-194226.log
The fact that it works in .Net 8 tells me it's a runtime bug, but it would be good to isolate the issue before passing it over to them.
Do you observe the same behavior when using a single call to the benchmark runner? E.g.
BenchmarkRunner.Run
([
BenchmarkConverter.TypeToBenchmarks(typeof(CollectionCreatingBenchmark), config),
BenchmarkConverter.TypeToBenchmarks(typeof(CollectionCreatingLoopBenchmark), config)
]);
Very strange that your log file ends with
WorkloadPilot 1: 16 op, 3165000.00 ns, 197.8125 us/op
WorkloadPilot 2:
Like the runtime got stuck while writing the log.
Would a minimal repro repo help? I can provide one.
@RealDotNetDave Is it able to provide reproducible sample code? If it's provided. I'll try to investigate it.
@RealDotNetDave Is this issue can be reproduced on .NET 10 RTM version?
If it able to provide reproducible sample code. I'll try investigate issue.
Does it still repro on v0.15.8? @filzrev fixed some process bugs (#2877, #2878).