Description
Description
There seem to be a memory leak if a singleton registered in a child container depend on a singleton in the parent container via an interface. See example.
Using parentContainer.RegisterType<IA, A>(new ContainerControlledLifetimeManager()); solves the memory issue, but causes IA and A to resolve to different objects.
I would have expected some way to register both IA and A so they resolve the same object, and that all objects in a child container to be released when that child container is disposed.
Discovered this problem when upgrading from 4.0.1 to 5.8.6, but 5.8.11 has the same problem.
To Reproduce
public interface IA { }
class A : IA { }
class B
{
public IA A { get; }
public B(IA a)
{
A = a;
}
}
class Program
{
static void Main(string[] args)
{
using (var parentContainer = new UnityContainer())
{
parentContainer.RegisterType<A>(new ContainerControlledLifetimeManager());
parentContainer.RegisterType<IA, A>();
using (var childContainer = parentContainer.CreateChildContainer())
{
childContainer.RegisterSingleton< B>();
var b = childContainer.Resolve<B>();
Console.WriteLine("ia == a: " + (childContainer.Resolve<IA>() == childContainer.Resolve<A>()));
}
// B is kept alive by the parentContainer
Console.WriteLine("Press any key");
Console.ReadKey();
}
}
}
Additional context
Creating a memory snapshot after the child container has been disposed reveals the B object still being alive. dotMemory reports the retention path as following:
Retention path of UnityMemoryLeak.B
Unity.UnityContainer._registrations ->
Unity.Storage.HashRegistry<System.Type, Unity.Storage.IRegistry<System.String, Unity.Policy.IPolicySet>>.Entries ->
Unity.Storage.HashRegistry+Entry<System.Type, Unity.Storage.IRegistry<System.String, Unity.Policy.IPolicySet>>[37] at [5].Value ->
Unity.Storage.LinkedRegistry.Value ->
Unity.Registration.ContainerRegistration.Next ->
Unity.Storage.LinkedNode<System.Type, Unity.Policy.IBuilderPolicy>.Value ->
Unity.ObjectBuilder.BuildPlan.DynamicMethod.DynamicMethodBuildPlan._buildMethod ->
Unity.ObjectBuilder.BuildPlan.DynamicMethod.DynamicBuildPlanMethod._target ->
Unity.Strategies.BuildKeyMappingStrategy+<>c__DisplayClass0_0.context ->
Unity.Builder.BuilderContext.k__BackingField ->
Unity.Builder.BuilderContext.k__BackingField ->
UnityMemoryLeak.B