Closed dotnetjunkie closed 2 years ago
The tricky part here is to ensure CyclicDependencyValidator
instances are disposed in cases where GetInstance
is not called on the InstanceProducer
, which will be the majority of cases. Most registrations are dependencies (not root types) and for those dependencies InstanceProducer.BuildExpression()
is called, but not InstanceProducer.GetInstance()
. After calling BuildExpression
the CyclicDependencyValidator
is not removed, because:
only if GetInstance has been called we can know for sure that there's no cyclic dependency. There could be a 'runtime cyclic dependency' caused by a registered delegate that calls back into the container manually. This will not be detected during building the expression, because the delegate won't (always) get executed at this point. [source: comment on line 361 of InstanceProducer.cs]
I think this issue about ThreadLocal
is probably related to this
Awesome work.
Simple Injector's internally creates a
CyclicDependencyValidator
instance per registration. EachCyclicDependencyValidator
uses its ownThreadLocal<bool>
instance, but this causes severe memory pressure (leak) when uses in combination with a large amount of registrations or with a large amount of container instances.Related:
A
ThreadLocal<T>
causes a memory leak in case its not disposed of properly. Although the amount of memory isn't that big, it will count up in case manyThreadLocal<T>
instances are created, as is the case with theCyclicDependencyValidator
. EachInstanceProducer
has its ownCyclicDependencyValidator
intance, and although theInstanceProducer
removes the reference to itsCyclicDependencyValidator
when its no longer of use, the underlyingThreadLocal<bool>
is not disposed of.This causes memory issues as reported by @andreminelli here: