-
-
Notifications
You must be signed in to change notification settings - Fork 844
Description
I've run into something that is either a memory leak or an unsupported use case, and I'm looking for guidance on which.
My application has a plugin model that loads assemblies into collectible AssemblyLoadContexts. It has a base lifetime scope built from core types loaded into the default ALC (including the Autofac types), and a nested lifetime scope built from types in assemblies in the collectible ALC. Requests are served from a third level of short-lived lifetime scopes based off the "current" plugin lifetime scope. Under certain conditions a new collectible ALC and plugin lifetime scope are constructed to replace the existing one, which is then disposed. Unfortunately, this leaks.
The source of the leaks is Autofac's reflection caches:
Autofac.Core.Activators.Reflection.ConstructorBinder.FactoryCache
Autofac.Core.Activators.Reflection.DefaultConstructorFinder.DefaultPublicConstructorsCache
Autofac.Util.TypeExtensions.IsGenericEnumerableInterfaceCache
Autofac.Util.TypeExtensions.IsGenericListOrCollectionInterfaceTypeCache
Autofac.Util.TypeExtensions.IsGenericTypeDefinedByCache
There may well be others, but using reflection to clear these caches fixes the leak in my test harness, and my ALCs successfully unload. To elaborate slightly, these are all static ConcurrentDictionaries that cache reflection information from the collectible ALCs, holding references and preventing unloading.
Is the intention that Autofac be usable with types in collectible ACLs? Is my hacky fix safe?
I'm happy to provide a test or test harness if this is considered a bug.