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

Memory leak on MS DI with Disposable Transient #429

Closed
YZahringer opened this issue Oct 5, 2021 · 6 comments
Closed

Memory leak on MS DI with Disposable Transient #429

YZahringer opened this issue Oct 5, 2021 · 6 comments
Assignees
Milestone

Comments

@YZahringer
Copy link

YZahringer commented Oct 5, 2021

I think there is a memory leak with Microsoft Dependency Injection adapter with the Transient disposable types.
I try it with/without MS DI and with/without Disposable type, the memory leak occurs only with MS DI and Disposable type.

Currently we use DryIoc with Prism on Xamarin.Forms multiplatform application. This bug produces a big memory leak, all VM are never released.

static void Main()
{
    // Default Container
    // Disposable: FALSE
    using (var container = new Container())
    {
        container.Register<NotDisposableViewModel>(Reuse.Transient);
        ResolveManyTimes(container, typeof(NotDisposableViewModel));
        Debugger.Break(); // No VM instances in memory 
    }

    // Default Container
    // Disposable: TRUE
    using (var container = new Container(Rules.Default.WithoutThrowOnRegisteringDisposableTransient()))
    {
        container.Register<DisposableViewModel>(Reuse.Transient);
        ResolveManyTimes(container, typeof(DisposableViewModel));
        Debugger.Break(); // No VM instances in memory
    }

    // MS DI Adapter
    // Disposable: FALSE
    using (var container = new Container().WithDependencyInjectionAdapter(new ServiceCollection().AddTransient<NotDisposableViewModel>()))
    {
        ResolveManyTimes(container, typeof(NotDisposableViewModel));
        Debugger.Break(); // No VM instances in memory
    }

    // MS DI Adapter
    // Disposable: TRUE
    using (var container = new Container().WithDependencyInjectionAdapter(new ServiceCollection().AddTransient<DisposableViewModel>()))
    {
        ResolveManyTimes(container, typeof(DisposableViewModel));
        Debugger.Break(); // 100 VM instances in memory (MEMORY LEAK!!!)
    }

    // MS DI Adapter with Scope
    // Disposable: TRUE
    using (var container = new Container().WithDependencyInjectionAdapter(new ServiceCollection().AddTransient<DisposableViewModel>()))
    {
        using (var scope = container.OpenScope())
        {
            ResolveManyTimes(scope, typeof(DisposableViewModel));
        }
        Debugger.Break(); // No VM instances in memory
    }

    // MS DI Adapter and Register on Default Container
    // Disposable: TRUE
    using (var container = new Container().WithDependencyInjectionAdapter(new ServiceCollection()))
    {
        container.Register<DisposableViewModel>(Reuse.Transient);
        ResolveManyTimes(container, typeof(DisposableViewModel));
        Debugger.Break(); // 100 VM instances in memory (MEMORY LEAK!!!)
    }

    Console.Read();
}

private static void ResolveManyTimes(IResolver container, Type typeToResolve)
{
    for (var i = 0; i < 100; i++)
    {
        container.Resolve(typeToResolve);
    }
}

internal class NotDisposableViewModel
{

}

internal class DisposableViewModel : IDisposable
{
    public void Dispose()
    {
    
    }
}

Output from VS Memory Analyzer:
image

@dadhi
Copy link
Owner

dadhi commented Oct 5, 2021

@YZahringer Hi, thanks for the interesting observation and detailed repros.

The problem is known and is laying in MS.DI rules including WithTrackingDisposableTransients, so the disposable transients will be stored in the nearest scope or in the container singleton scope until either scope or container is disposed.

You may suppress the rule applying the WithoutTrackingDisposableTransients() after the WithDependencyInjectionAdapter(...), or you may change the Transient for something else to be more explicit about VM lifetime.

@YZahringer
Copy link
Author

YZahringer commented Oct 6, 2021

@dadhi Thanks for the quick answer. I can't find the WithoutTrackingDisposableTransients() method, only WithTrackingDisposableTransients is available.

This one is missing or planned for a future release?
Is there another way to remove this rule without this method?

@dadhi
Copy link
Owner

dadhi commented Oct 6, 2021

I cannot find WithoutTrackingDisposableTransients

Then let's add it.
There also a wrong api-doc on WithTracking... counterpart.
Plus let's document the MS.DI rules and important consequences.

@SeriousM
Copy link
Contributor

SeriousM commented Oct 8, 2021

I also have a memoryleak and I suspect that MS.DI is a vital part in my story but wasn't able to verify it yet.
What is the downside of WithoutTrackingDisposableTransients in combination with MS.DI?

@dadhi
Copy link
Owner

dadhi commented Oct 8, 2021

@SeriousM Likely, yes. Fix will be soon.

@dadhi dadhi self-assigned this Oct 9, 2021
@dadhi dadhi added this to the v4.8.2 milestone Oct 9, 2021
@dadhi dadhi closed this as completed in d842eb0 Oct 9, 2021
@dadhi
Copy link
Owner

dadhi commented Oct 9, 2021

Added the WithoutTrackingDisposableTransients, corrected the docs, documented the rule list and released the v4.8.2

dadhi added a commit that referenced this issue Oct 10, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants