Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance & Memory Issue on container setup #1446

Open
SamuelMuellerKMS opened this issue Feb 13, 2025 · 5 comments
Open

Performance & Memory Issue on container setup #1446

SamuelMuellerKMS opened this issue Feb 13, 2025 · 5 comments

Comments

@SamuelMuellerKMS
Copy link

Describe the Bug

In the Configure method of the Module class (https://github.com/autofac/Autofac/blob/develop/src/Autofac/Module.cs#L53), event handlers are always created for the events ‘componentRegistry.RegistrationSourceAdded’ & ‘componentRegistry.Registered’.
However, if the feature is not required at all, this leads to poor performance when setting up the container with a large number of modules. It also leads to high memory consumption.

Steps to Reproduce

I've created a Benchmark to reproduce this

public class SetupContainerBenchmark
{
    private IContainer _container;

    [Benchmark]
    public void SetupContainerWith10000Modules()
    {
        var builder = new ContainerBuilder();
        for (var i = 0; i < 10000; i++)
        {
            builder.RegisterModule<SimpleModule>();
        }

        _container = builder.Build();
    }
}
internal class SimpleModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        base.Load(builder);

        builder.RegisterType<SampleType>().AsSelf();
    }
}
internal class SampleType;

BenchmarkDotNet v0.14.0, Windows 11 (10.0.26100.2894)
12th Gen Intel Core i9-12900HK, 1 CPU, 20 logical and 14 physical cores
.NET SDK 8.0.405
[Host] : .NET 8.0.12 (8.0.1224.60305), X64 RyuJIT AVX2 [AttachedDebugger]
DefaultJob : .NET 8.0.12 (8.0.1224.60305), X64 RyuJIT AVX2

Origin Result:

Method Mean Error StdDev Gen0 Gen1 Allocated
SetupContainerWith10000Modules 1.594 s 0.0476 s 0.1403 s 133000.0000 24000.0000 1.56 GB

If i remove the Event Registration:

Method Mean Error StdDev Gen0 Gen1 Gen2 Allocated
SetupContainerWith10000Modules 73.26 ms 1.942 ms 5.509 ms 5250.0000 2375.0000 750.0000 55.32 MB

Expected Behavior

It would be useful if you could prevent the Event Registration if not needed, to increase the container setup performance and to decrease the memoery usage

Dependency Versions

Autofac: 8.2

@tillig
Copy link
Member

tillig commented Feb 13, 2025

Have you tried creating your own custom IModule base class that skips the events you don't want?

We'd be happy to take a pull request, but I'm not sure we'd want to have a bunch of extra properties to say "this is enabled and this is disabled" on every module. The vast majority of the time this is pretty low impact - very, very few solutions are loading 10K modules, and even if they are, 1s startup time isn't wrecking anyone's day in a solution of that size. I'm not sure I'd want to add a confusing API to support an infrequent use case. Implementing your own IModule is the "official answer" to "I have a custom use case" for this sort of thing.

@SamuelMuellerKMS
Copy link
Author

Yes i've allready tried that, but i couldn't rebuild the same functionality becaust the constructor of the ContainerBuilder is internal. Is there another way to rebuild this functionality?

I agree with you that the scenario with the 10000 Modules is rare, but in our application the build of the container lasts between 5s and 15s. So we would be happy to save some time :-)

@tillig
Copy link
Member

tillig commented Feb 14, 2025

I see what you're saying. Looks like this may be a remnant from making containers immutable - we had to lock that down to avoid folks changing containers mid-runtime but it looks like we lost the ability to abstract modules on the way. Hmmm.

For folks reading, the issue is that there's not a great way to create a new ContainerBuilder that attaches to an existing IComponentRegistry, which means the logic in Module can't easily be replicated.

I wonder if there's a way to update AttachToRegistrations and AttachToSources to be smarter, like to query to see if the Module being registered has overridden the AttachToComponentRegistration or AttachToRegistrationSource first and then only add the handler if there's an override. No override means there's no handler required; and if it's smart enough, it wouldn't require anyone set flags or configure extra stuff - it'd just "do the right thing."

@tatva-savan
Copy link

@tillig - Do we have any solution for this or a workaround? We would have a similar performance behavior where we are registering 400+ classes and Autofac is taking 3+ secs for this.

Unfortunately, I'm not able to share code with for it. But we can clearly observed the time consumption with it.
Here I am sharing a high level code that we are generally used.

  • containerBuilder.RegisterType<MyClass>().As<IMyClass>();
  • containerBuilder.RegisterType<MyClass1>().AsSelf();
  • containerBuilder.RegisterModule(new MainModule());
  • containerBuilder.RegisterType<MyClass2>().InstancePerLifetimeScope().WithAttributeFiltering();

I had also checked some documentation but no luck with it. e.g. Register Frequently-Used Components with Lambdas

I believe, it would have the similar issue that @SamuelMuellerKMS mentioned here.

@tillig
Copy link
Member

tillig commented Feb 18, 2025

@tatva-savan The issue here would only affect module registrations, not other registrations. Unless you're registering 10,000 or more modules, this isn't it.

To be clear, there is no one I'm aware of actively working this issue. Registering 10,000 modules is an edge case at best and saving 1s on startup time in that edge case doesn't quite make this an imminent priority. I posted some thoughts about what I think the solution is; if folks can't wait for the fix, a PR would be a great way to help get that done faster.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants