Memoryleak if a singleton never accesses a lazy dependency
Issue #350
new
When an object that is registered as singleton has a lazy dependency which is never accessed the application will leak memory. I can replicate this with Delphi 10.2 and 10.4 with the latest develop version of Spring4D (ecb65cf0da6177c0a3da4ca6610efdc902215808).
Not using .AsSingleton or always accessing the lazy does fix the problem but I see no reason it shouldn’t work the way I intended to use it.
The leak information looks like this:
5 - 12 bytes: Unbekannt x 6
13 - 20 bytes: Unbekannt x 3
21 - 28 bytes: LazySingleton.TL1 x 1
, Unbekannt x 1
37 - 44 bytes: Spring.Collections.Base.TInnerCollection<Spring.Container.Core.TComponentModel> x 1
, Spring.Collections.Base.TInnerCollection<System.Rtti.TValue> x 1
, Spring.Collections.Events.TCollectionChangedEventImpl<System.Rtti.TValue> x 1
, Spring.Collections.Events.TCollectionChangedEventImpl<Spring.Container.Core.TComponentModel> x 1
, Spring.Collections.Events.TCollectionChangedEventImpl<System.TObject> x 1
, Unbekannt x 1
45 - 52 bytes: Spring.Container.CreationContext.TCreationContext x 1
, System.SysUtils.TMultiReadExclusiveWriteSynchronizer x 1
, Spring.Collections.Stacks.TFoldedStack<System.TObject> x 1
, Spring.Collections.Lists.TList<System.Rtti.TValue> x 1
, Spring.Collections.Lists.TList<Spring.TNamedValue> x 1
, Spring.Collections.Lists.TList<Spring.TTypedValue> x 1
61 - 68 bytes: Spring.Container.Resolvers.@TLazyResolver.InternalResolve$ActRec<System.IInterface> x 1
69 - 76 bytes: System.SysUtils.TThreadLocalCounter x 1
117 - 124 bytes: Spring.Collections.Dictionaries.TDictionary<Spring.Container.Core.TComponentModel,System.Rtti.TValue> x 1
189 - 204 bytes: Unbekannt x 1
Comments (2)
-
repo owner -
repo owner - changed milestone to 2.1
- Log in to comment
Thanks, that issue is known to me.
Here is the reason why this currently happens: the factory attached to the lazy provided by the container has a reference to a creationcontext instance. That context keeps information during the resolve process which includes any singleton or perresolve instances from that resolve operation to avoid recreating them.
That causes roughly this dependency graph: TL1 → Lazy<IL2> → factory → creationcontext → TL1 and thus we have a nice circular reference of strong references.
The current design of the creationcontext and the way lazy resolutions cause it to live way beyond the initial resolve operation is unideal to say the least. The way singletons are currently handled by the container plays into this so a fix is not easy at this point.
However Container refactoring is planned for the next big version after 2.0.
Here is a workaround that you can use meanwhile: Implement
Spring.Container.Common.IDisposable
in TL1 and set FL2 to nil in theDispose
method. That is then being called on all singleton instance when the container is destroyed and thus breaks the circular dependencies.