Skip to content
This repository was archived by the owner on Nov 2, 2018. It is now read-only.

Make ServiceScope track list of IDisposable as WeakReference #580

Closed
nh43de opened this issue Sep 11, 2017 · 5 comments
Closed

Make ServiceScope track list of IDisposable as WeakReference #580

nh43de opened this issue Sep 11, 2017 · 5 comments

Comments

@nh43de
Copy link

nh43de commented Sep 11, 2017

Problem: memory leak caused by references to disposed objects in service scope
Summary: We have found that the DI container service scope will hold onto objects that have been disposed, preventing them from being garbage collected.
Location: DependencyInjection/src/DI/ServiceLookup/ServiceProviderEngineScope.cs
Field: _disposables
Root Cause: DI container reference to disposed objects prevents them from being garbage collected
Proposed Solution: replace List to IWeakCollection - collection of weak references. I'm not sure if this is compatible with the design intentions of MS DI.

In ServiceProviderEngineScope.cs, we are tracking a List to track objects that will be disposed when the service scope is disposed. However, this can cause objects that have already been disposed to be retained by the garbage collector, even if the only reference to the object is in the DI container service scope.

In our fork of the project, we have replaced the List with Stephen Cleary's IWeakCollection, and have found that the memory leak goes away. Also, all unit tests pass. This way, the DI container's internal reference to the object does not make the GC consider them as rooted.

http://nitokitchensink.codeplex.com/sourcecontrol/changeset/view/27265#453683

@khellang
Copy link
Contributor

This sounds completely opposite of how scopes are intended to be used. A scope is meant to have a short lifetime (typically a request lifetime). The tracked disposables are owned by the container and are supposed to be diposed by the container.

The solution here would be to register the services as transient and use the container for activation, but take ownership and track instances for disposal yourself. So if you're talking about transient instances, I completely agree with you. In fact, I don't even think transients should be tracked at all (see #456). Unfortunately, the linked issue has been closed, so I wouldn't hold my breath for a fix for these memory leaks in the near future...

@nh43de
Copy link
Author

nh43de commented Sep 11, 2017

I was talking about transient services. If we are going to track them, making them weak references allows for GC to collect them when they are no longer referenced and have been disposed.

@dotnetjunkie
Copy link

@nh43de It is the responsibility of the Scope to dispose disposable instances. For it to be able to do this, it requires a (hard) reference to such object. Changing the reference to a weak reference might cause the Scope to lose the reference to it, which makes it impossible for it to call Dispose on such object. This by itself could cause problems such as connection pool timeouts and out of memory problems, because of the undeterministic nature of the GC concerning the invocation of Finalizer methods that need to be called in the absense of a call to Dispose().

@nh43de
Copy link
Author

nh43de commented Oct 6, 2017

@dotnetjunkie Thanks for the enlightening comments and I really appreciate you taking the time to respond. This scenario definitely makes sense, and something probably best avoided in favor of proper scope handling.

@aspnet-hello
Copy link

This issue was moved to dotnet/aspnetcore#2336

@aspnet aspnet locked and limited conversation to collaborators Jan 1, 2018
@aspnet-hello aspnet-hello removed this from the Discussions milestone Jan 1, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants