Skip to content

Memory leak after configuration disposal from PhysicalFileProvider #86146

@MaceWindu

Description

@MaceWindu

Description

When application creates many short-living configuration roots, which use files it results in memory leaks around FileSystemWatcher class (in our case we setup test environment for each test and it leads to memory/performance issues as we have around 100k tests).

I've checked code and see that while ConfigurationRoot.Dispose disposes IConfigurationProvider instances, FileConfigurationProvider.Dispose disposes only _changeTokenRegistration and file (folder actually) watch infrastructure in FileConfigurationSource is never disposed.

Reproduction Steps

internal class Program
	{
		static void Main()
		{
			const int iterations = int.MaxValue;

			for (var i = 0; i < iterations; i++)
			{
				Test();
			}
		}

		static void Test()
		{
			var config = new ConfigurationBuilder().AddXmlFile("settings.xml", false, true).Build();

			(config as IDisposable)?.Dispose();
		}
	}

Expected behavior

No memory leaks

Actual behavior

Memory leaks

We need to support two runtimes currently, so results are for .NET7 and NET48

.NET 7 runtime after ~78k iterations
image
where byte[] instances are
image

In NETFX 4.8 situation is even worse (expected, as it doesn't have all improvements to file watcher related code)
image

Regression?

Nope

Known Workarounds

passing external PhysicalFileProvider instance and dispose it explicitly fixes leak completely:

using var fileProvider = new PhysicalFileProvider(AppContext.BaseDirectory);
using var config = new ConfigurationBuilder().AddXmlFile(fileProvider, "settings.xml", false, true).Build() as IDisposable;

Configuration

No response

Other information

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions