You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In an IOC environment, a child object exposes some events, the parent object start listening to these events, and stops when disposed.
When the parent is disposed an event detach is performed, but NSubstitute keeps some reference and do not allow the parent object to be collected from the GC, leading in memory leaks.
Hi @Jekops,
Thank you for the great repro! I copied the relevant parts below
publicclassParent:IDisposable{privateIChildm_Child;publicParent(IChildchild){m_Child=child;m_Child.Changed+=Child_Changed;}publicvoidDispose(){m_Child.Changed-=Child_Changed;m_Child=null;}privatevoidChild_Changed(objectsender,EventArgsargs){}}publicclassParentTest:IDisposable{// this field holds a reference to the substitute created below// the object is still available in the Dispose method and not reclaimed by GC yet// because this instance of ParentTest is still aliveprivateIChildm_Child;privateParentm_SUT;publicParentTest(){m_Child=Substitute.For<IChild>();m_SUT=newParent(m_Child);}publicvoidDispose(){m_SUT.Dispose();m_SUT=null;// }}
NSubstitute keeps the state and setup in its instances. It's an instance of IChild substitute in this case. When you subscribe to the event with m_Child.Changed += Child_Changed; it also keeps a reference to the current instance of the Parent class.
The observed behavior happens because an instance of the ParentTest test class keep a reference to the substitute and its state in its field m_Child. So it looks like this xUnit -> ParentTest -> Substitute.For<IChild> -> Parent. The field will be reclaimed by GC after the ParentTest (note: oversimplified, GC is a complex beast).
Or you can assign the field to null in your Dispose method then you will get what you want:
Describe the bug
In an IOC environment, a child object exposes some events, the parent object start listening to these events, and stops when disposed.
When the parent is disposed an event detach is performed, but NSubstitute keeps some reference and do not allow the parent object to be collected from the GC, leading in memory leaks.
To Reproduce
Here you can find an example.
NSubstituteTester.zip
Expected behaviour
When a concrete class detach the events from a substitute child class, the concrete class should be able to be collected by the GC.
Environment:
The text was updated successfully, but these errors were encountered: