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

[BUG] MemoryLeak on WPF #3091

Closed
tomasfil opened this issue Dec 6, 2021 · 18 comments · Fixed by #3105
Closed

[BUG] MemoryLeak on WPF #3091

tomasfil opened this issue Dec 6, 2021 · 18 comments · Fixed by #3105
Labels

Comments

@tomasfil
Copy link
Contributor

tomasfil commented Dec 6, 2021

Describe the bug

Ok, I did have some investigation on Slack the other day with Annie.

There is something keeping ViewModels and Views from ReactiveUI in memory causing MemoryLeak.

Solution provided in repository might seems drastic. In project where I discovered it the ViewModels and Views eat up much more memory, so fraction % of them leaked causes to grow application into hundreds MB in RAM.

I was unable to find the cause of this.

In screenshots I you can see snapshots from dotMemory running without Visual Studio completely. So it is not caused by visual studio debugger as I thought.

I did test it on NET 5 -16.4.1
and NET 6 - 17.1.4
Both have the issue present (my main project is on 16.4.1, because I need to wait for Oracle Entity framework Core 6 to release, before I can upgrade.)

Steps To Reproduce

Run this project, and wait few seconds.

https://github.com/tomasfil/ReactiveUI_MemoryLeakTest_Wpf

Expected behaviour

No memory leak. Pun inteded

Screenshots

image
image
image

Environment

  • OS: Windows
  • Version 20H2
  • Device: Laptop
  • ReactiveUI Version: 16.4.1, 17.1.4

Additional context

@tomasfil tomasfil added the bug label Dec 6, 2021
@ChrisPulman
Copy link
Member

Thanks for the detailed information, we will take a look at this. Was there a version that did work with no leaks?

@tomasfil
Copy link
Contributor Author

tomasfil commented Dec 6, 2021

@ChrisPulman I dont know. I dont have live project of anything with ReactiveUI.
I am rewriting few .NET 4.6.1 apps to move to .NET5 and then .NET6 (once oracle EF core 6 comes out) and I am now stuck on this. It is Pilot project with Domain and business logic structure rewritten from scratch with ReactiveUI.

I figured it out just after the first app was running in production for few days.
I had to take it back and give users old .NET framework app

@tomasfil
Copy link
Contributor Author

tomasfil commented Dec 6, 2021

Just a heads up. It is nothing to do with the Virtualizing itemscontrol template, the same is happening with just:

        <ItemsControl x:Name="TestIC" Grid.Row="1" ></ItemsControl>

@ChrisPulman
Copy link
Member

I ran a quick test from V10 through to the latest V17 and the same issue persists. I will look deeper into this to see if I can locate the source of the memory increase.

@anaisbetts
Copy link
Member

This seems related to Dependency Properties leaking:

From my modified version of the repro that:

  • Removes virtualization
  • Switches DD SourceCache => simple ObservableCollection
  • Fully initializes ReactiveUI
0:018> !gcroot 000001a7263349e8 
Thread 939c:
    000000802ED7D850 00007FF80900BEC4 System.Reactive.Linq.ObservableImpl.Do`1+OnNext+_[[System.__Canon, System.Private.CoreLib]].OnNext(System.__Canon) [/_/Rx.NET/Source/src/System.Reactive/Linq/Observable/Do.cs @ 38]
        rsi: 
            ->  000001A726980C28 ReactiveUI_MemoryLeakTest_Wpf.ViewModels.TestViewModel
            ->  000001A726980308 ReactiveUI_MemoryLeakTest_Wpf.Models.TestModel
            ->  000001A7269805C8 ReactiveUI.IReactiveObjectExtensions+ExtensionState`1[[ReactiveUI_MemoryLeakTest_Wpf.Models.TestModel, ReactiveUI_MemoryLeakTest_Wpf]] (dependent handle)
            ->  000001A726980668 System.Lazy`1[[System.Reactive.Subjects.Subject`1[[System.Reactive.Unit, System.Reactive]], System.Reactive]]
            ->  000001A7269E2290 System.Reactive.Subjects.Subject`1[[System.Reactive.Unit, System.Reactive]]
            ->  000001A7269E3230 System.Reactive.Subjects.Subject`1+SubjectDisposable[[System.Reactive.Unit, System.Reactive]][]
            ->  000001A7269E3210 System.Reactive.Subjects.Subject`1+SubjectDisposable[[System.Reactive.Unit, System.Reactive]]
            ->  000001A7269E31F0 System.Reactive.Linq.ObservableImpl.Merge`1+Observables+_+InnerObserver[[System.Reactive.Unit, System.Reactive]]
            ->  000001A7269E2DA0 System.Reactive.Linq.ObservableImpl.Merge`1+Observables+_[[System.Reactive.Unit, System.Reactive]]
            ->  000001A7269E2D88 System.Reactive.Linq.ObservableImpl.Buffer`2+Boundaries+_+BufferClosingObserver[[ReactiveUI.IReactivePropertyChangedEventArgs`1[[ReactiveUI_MemoryLeakTest_Wpf.Models.TestModel, ReactiveUI_MemoryLeakTest_Wpf]], ReactiveUI],[System.Reactive.Unit, System.Reactive]]
            ->  000001A7269E2CD8 System.Reactive.Linq.ObservableImpl.Buffer`2+Boundaries+_[[ReactiveUI.IReactivePropertyChangedEventArgs`1[[ReactiveUI_MemoryLeakTest_Wpf.Models.TestModel, ReactiveUI_MemoryLeakTest_Wpf]], ReactiveUI],[System.Reactive.Unit, System.Reactive]]
            ->  000001A7269E2CB0 System.Reactive.Linq.ObservableImpl.SelectMany`2+EnumerableSelector+_[[System.Collections.Generic.IList`1[[ReactiveUI.IReactivePropertyChangedEventArgs`1[[ReactiveUI_MemoryLeakTest_Wpf.Models.TestModel, ReactiveUI_MemoryLeakTest_Wpf]], ReactiveUI]], System.Private.CoreLib],[ReactiveUI.IReactivePropertyChangedEventArgs`1[[ReactiveUI_MemoryLeakTest_Wpf.Models.TestModel, ReactiveUI_MemoryLeakTest_Wpf]], ReactiveUI]]
            ->  000001A7269E2C90 System.Reactive.Linq.ObservableImpl.AsObservable`1+_[[ReactiveUI.IReactivePropertyChangedEventArgs`1[[ReactiveUI_MemoryLeakTest_Wpf.Models.TestModel, ReactiveUI_MemoryLeakTest_Wpf]], ReactiveUI]]
            ->  000001A7269E2390 System.Reactive.Subjects.Subject`1[[ReactiveUI.IReactivePropertyChangedEventArgs`1[[ReactiveUI_MemoryLeakTest_Wpf.Models.TestModel, ReactiveUI_MemoryLeakTest_Wpf]], ReactiveUI]]
            ->  000001A7269F00C8 System.Reactive.Subjects.Subject`1+SubjectDisposable[[ReactiveUI.IReactivePropertyChangedEventArgs`1[[ReactiveUI_MemoryLeakTest_Wpf.Models.TestModel, ReactiveUI_MemoryLeakTest_Wpf]], ReactiveUI]][]
            ->  000001A7269E2C50 System.Reactive.Subjects.Subject`1+SubjectDisposable[[ReactiveUI.IReactivePropertyChangedEventArgs`1[[ReactiveUI_MemoryLeakTest_Wpf.Models.TestModel, ReactiveUI_MemoryLeakTest_Wpf]], ReactiveUI]]
            ->  000001A7269E2C00 System.Reactive.Linq.ObservableImpl.RefCount`1+Eager+_[[ReactiveUI.IReactivePropertyChangedEventArgs`1[[ReactiveUI_MemoryLeakTest_Wpf.Models.TestModel, ReactiveUI_MemoryLeakTest_Wpf]], ReactiveUI]]
            ->  000001A7269E2BE0 System.Reactive.Linq.ObservableImpl.Cast`2+_[[System.Object, System.Private.CoreLib],[ReactiveUI.IReactivePropertyChangedEventArgs`1[[ReactiveUI.IReactiveObject, ReactiveUI]], ReactiveUI]]
            ->  000001A7269E2BB8 System.Reactive.Linq.ObservableImpl.Where`1+Predicate+_[[ReactiveUI.IReactivePropertyChangedEventArgs`1[[ReactiveUI.IReactiveObject, ReactiveUI]], ReactiveUI]]
            ->  000001A7269E2B90 System.Reactive.Linq.ObservableImpl.Select`2+Selector+_[[ReactiveUI.IReactivePropertyChangedEventArgs`1[[ReactiveUI.IReactiveObject, ReactiveUI]], ReactiveUI],[ReactiveUI.ObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A7269E2620 System.Reactive.Linq.ObservableImpl.Concat`1+_[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A7269E25F8 System.Reactive.Linq.ObservableImpl.Select`2+Selector+_[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI],[ReactiveUI.ObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A7269E25D0 System.Reactive.Linq.ObservableImpl.Switch`1+_+InnerObserver[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A7269E1690 System.Reactive.Linq.ObservableImpl.Switch`1+_[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A7269E1668 System.Reactive.Linq.ObservableImpl.Where`1+Predicate+_[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A7269E1640 System.Reactive.Linq.ObservableImpl.Select`2+Selector+_[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI],[ReactiveUI.ObservedChange`2[[ReactiveUI_MemoryLeakTest_Wpf.ViewModels.TestViewModel, ReactiveUI_MemoryLeakTest_Wpf],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A7269E1600 System.Reactive.Linq.ObservableImpl.DistinctUntilChanged`2+_[[ReactiveUI.ObservedChange`2[[ReactiveUI_MemoryLeakTest_Wpf.ViewModels.TestViewModel, ReactiveUI_MemoryLeakTest_Wpf],[System.Object, System.Private.CoreLib]], ReactiveUI],[System.Object, System.Private.CoreLib]]
            ->  000001A7269E15D8 System.Reactive.Linq.ObservableImpl.Select`2+Selector+_[[ReactiveUI.IObservedChange`2[[ReactiveUI_MemoryLeakTest_Wpf.ViewModels.TestViewModel, ReactiveUI_MemoryLeakTest_Wpf],[System.Object, System.Private.CoreLib]], ReactiveUI],[System.Object, System.Private.CoreLib]]
            ->  000001A7269E15B0 System.Reactive.Linq.ObservableImpl.Switch`1+_+InnerObserver[[System.Object, System.Private.CoreLib]]
            ->  000001A7269DFC78 System.Reactive.Linq.ObservableImpl.Switch`1+_[[System.Object, System.Private.CoreLib]]
            ->  000001A7269DFBC0 System.Reactive.Linq.ObservableImpl.SelectMany`2+ObservableSelector+_[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]]
            ->  000001A7269DFB60 System.Reactive.Linq.ObservableImpl.CombineLatest`3+_+FirstObserver[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib],[<>f__AnonymousType0`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A7269DFB08 System.Reactive.Linq.ObservableImpl.CombineLatest`3+_[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib],[<>f__AnonymousType0`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A7269DFAE0 System.Reactive.Linq.ObservableImpl.Where`1+Predicate+_[[<>f__AnonymousType0`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A7269DFAB8 System.Reactive.Linq.ObservableImpl.Select`2+Selector+_[[<>f__AnonymousType0`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI],[System.String, System.Private.CoreLib]]
            ->  000001A7269DFA80 System.Reactive.AnonymousSafeObserver`1[[System.String, System.Private.CoreLib]]
            ->  000001A7269DFA10 System.Action`1[[System.Exception, System.Private.CoreLib]]
            ->  000001A7269DF5F8 ReactiveUI.PropertyBinderImplementation+<>c__DisplayClass11_0`3[[ReactiveUI_MemoryLeakTest_Wpf.Views.TestView, ReactiveUI_MemoryLeakTest_Wpf],[System.String, System.Private.CoreLib],[System.Object, System.Private.CoreLib]]
            ->  000001A7269C73E0 ReactiveUI_MemoryLeakTest_Wpf.Views.TestView
            ->  000001A724E885B8 System.Windows.Threading.Dispatcher
            ->  000001A724F60FB0 System.EventHandler
            ->  000001A724F60F18 System.Object[]
            ->  000001A724EE65C8 System.EventHandler
            ->  000001A724EE6558 System.Windows.ContextLayoutManager
            ->  000001A724F5B610 System.Windows.ContextLayoutManager+InternalMeasureQueue
            ->  000001A724F5CDF8 System.Windows.ContextLayoutManager+LayoutQueue+Request
            ->  000001A724F570D0 System.Windows.Controls.StackPanel
            ->  000001A724F550D8 System.Windows.Controls.ItemsPresenter
            ->  000001A724F55260 System.Windows.EffectiveValueEntry[]
            ->  000001A724EE4A60 ReactiveUI_MemoryLeakTest_Wpf.MainWindow
            ->  000001A724F603F8 System.Windows.EffectiveValueEntry[]
            ->  000001A724EF8878 System.Windows.EventHandlersStore
            ->  000001A724F60C68 MS.Utility.SixObjectMap
            ->  000001A724EE5C68 System.Windows.DependencyPropertyChangedEventHandler
            ->  000001A724EE5AA8 System.Windows.Input.Win32KeyboardDevice
            ->  000001A724EE5B90 MS.Internal.SecurityCriticalDataClass`1[[System.Windows.Input.InputManager, PresentationCore]]
            ->  000001A724EE58D8 System.Windows.Input.InputManager
            ->  000001A7269FAF60 System.Windows.Threading.DispatcherOperation
            ->  000001A7269FB088 System.Windows.Threading.PriorityItem`1[[System.Windows.Threading.DispatcherOperation, WindowsBase]]
            ->  000001A726A00880 System.Windows.Threading.PriorityItem`1[[System.Windows.Threading.DispatcherOperation, WindowsBase]]
            ->  000001A726A00758 System.Windows.Threading.DispatcherOperation
            ->  000001A724F085D8 System.Windows.Threading.DispatcherOperationCallback
            ->  000001A724F07C98 System.Windows.Media.MediaContext
            ->  000001A726A00AD8 MS.Utility.FrugalObjectList`1[[MS.Internal.LoadedOrUnloadedOperation, PresentationCore]]
            ->  000001A726A00AF0 MS.Utility.SingleItemList`1[[MS.Internal.LoadedOrUnloadedOperation, PresentationCore]]
            ->  000001A726A00AB0 MS.Internal.LoadedOrUnloadedOperation
            ->  000001A726981728 System.Windows.Controls.ContentPresenter
            ->  000001A7269C0ED8 System.Windows.EffectiveValueEntry[]
            ->  000001A7269832A0 System.Collections.Generic.List`1[[System.Windows.DependencyObject, WindowsBase]]
            ->  000001A7269832C0 System.Windows.DependencyObject[]
            ->  000001A7269839A8 ReactiveUI.ViewModelViewHost
            ->  000001A7269C5648 System.Windows.EffectiveValueEntry[]
            ->  000001A726988DF0 System.Windows.EventHandlersStore
            ->  000001A72698AFA8 MS.Utility.SixObjectMap
            ->  000001A726988E08 MS.Utility.FrugalObjectList`1[[System.Windows.RoutedEventHandlerInfo, PresentationCore]]
            ->  000001A726988E20 MS.Utility.SingleItemList`1[[System.Windows.RoutedEventHandlerInfo, PresentationCore]]
            ->  000001A726988D38 System.Windows.SizeChangedEventHandler
            ->  000001A726988D18 ReactiveUI.ViewModelViewHost+<>c__DisplayClass4_1
            ->  000001A726988CD8 System.Action`1[[System.String, System.Private.CoreLib]]
            ->  000001A726988C78 System.Reactive.Subjects.Subject`1[[System.String, System.Private.CoreLib]]
            ->  000001A7269C5158 System.Reactive.Subjects.Subject`1+SubjectDisposable[[System.String, System.Private.CoreLib]][]
            ->  000001A726988C98 System.Reactive.Subjects.Subject`1+SubjectDisposable[[System.String, System.Private.CoreLib]]
            ->  000001A7269888E8 System.Reactive.Linq.ObservableImpl.Concat`1+_[[System.String, System.Private.CoreLib]]
            ->  000001A7269888A8 System.Reactive.Linq.ObservableImpl.DistinctUntilChanged`2+_[[System.String, System.Private.CoreLib],[System.String, System.Private.CoreLib]]
            ->  000001A726988880 System.Reactive.Linq.ObservableImpl.Switch`1+_+InnerObserver[[System.String, System.Private.CoreLib]]
            ->  000001A726987200 System.Reactive.Linq.ObservableImpl.Switch`1+_[[System.String, System.Private.CoreLib]]
            ->  000001A726987258 System.Reactive.Linq.ObservableImpl.Select`2+Selector+_[[ReactiveUI.IObservedChange`2[[ReactiveUI.ViewModelViewHost, ReactiveUI.Wpf],[System.IObservable`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib]], ReactiveUI],[System.IObservable`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib]]
            ->  000001A726987280 System.Reactive.Linq.ObservableImpl.DistinctUntilChanged`2+_[[ReactiveUI.ObservedChange`2[[ReactiveUI.ViewModelViewHost, ReactiveUI.Wpf],[System.IObservable`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib]], ReactiveUI],[System.IObservable`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib]]
            ->  000001A7269872C0 System.Reactive.Linq.ObservableImpl.Select`2+Selector+_[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI],[ReactiveUI.ObservedChange`2[[ReactiveUI.ViewModelViewHost, ReactiveUI.Wpf],[System.IObservable`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib]], ReactiveUI]]
            ->  000001A7269872E8 System.Reactive.Linq.ObservableImpl.Where`1+Predicate+_[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A726987310 System.Reactive.Linq.ObservableImpl.Switch`1+_[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A7269883F0 System.Reactive.Linq.ObservableImpl.Switch`1+_+InnerObserver[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A726988418 System.Reactive.Linq.ObservableImpl.Select`2+Selector+_[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI],[ReactiveUI.ObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A726988440 System.Reactive.Linq.ObservableImpl.Concat`1+_[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A726988478 System.Collections.Generic.Stack`1[[System.Collections.Generic.IEnumerator`1[[System.IObservable`1[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]], System.Private.CoreLib]], System.Private.CoreLib]]
            ->  000001A7269884B8 System.Collections.Generic.IEnumerator`1[[System.IObservable`1[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]], System.Private.CoreLib]][]
            ->  000001A726988498 System.SZGenericArrayEnumerator`1[[System.IObservable`1[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]], System.Private.CoreLib]]
            ->  000001A726988390 System.IObservable`1[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]][]
            ->  000001A726988338 System.Reactive.Linq.QueryLanguage+CreateWithDisposableObservable`1[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]]
            ->  000001A7269882F8 System.Func`2[[System.IObserver`1[[ReactiveUI.IObservedChange`2[[System.Object, System.Private.CoreLib],[System.Object, System.Private.CoreLib]], ReactiveUI]], System.Private.CoreLib],[System.IDisposable, System.Private.CoreLib]]
            ->  000001A7269873B8 ReactiveUI.DependencyObjectObservableForProperty+<>c__DisplayClass1_0
            ->  000001A7250BAA08 System.ComponentModel.DependencyPropertyDescriptor
            ->  000001A7250D14F0 MS.Internal.ComponentModel.DependencyObjectPropertyDescriptor
            ->  000001A7250D26C8 System.Collections.Generic.Dictionary`2[[System.Windows.DependencyObject, WindowsBase],[MS.Internal.ComponentModel.PropertyChangeTracker, WindowsBase]]
            ->  000001A726867280 System.Collections.Generic.Dictionary`2+Entry[[System.Windows.DependencyObject, WindowsBase],[MS.Internal.ComponentModel.PropertyChangeTracker, WindowsBase]][]
            ->  000001A7263204C0 ReactiveUI.ViewModelViewHost
            ->  000001A7263348F0 System.Windows.EffectiveValueEntry[]
            ->  000001A7263349E8 ReactiveUI_MemoryLeakTest_Wpf.Views.TestView

Found 1 unique roots (run '!gcroot -all' to see all roots).

Removing the DataTemplate for the ItemsControl fixes the leak which also lends weight to this theory

@anaisbetts
Copy link
Member

anaisbetts commented Dec 6, 2021

https://github.com/reactiveui/ReactiveUI/blame/a8398a3ec886b1fc46876af5e7b1eb54dbad8fc5/src/ReactiveUI.Uwp/Common/ViewModelViewHost.cs#L111

Here we leak a subscription to a variable that eventually passes through a DependencyProperty, meaning that it never goes away

GitHub
An advanced, composable, functional reactive model-view-viewmodel framework for all .NET platforms that is inspired by functional reactive programming. ReactiveUI allows you to abstract mutable st...

@tomasfil
Copy link
Contributor Author

tomasfil commented Dec 6, 2021

Just a small question, if you find a fix, is it possible to get it to .net5 version? Since I am unable to upgrade

Removing the DataTemplate for the ItemsControl fixes the leak which also lends weight to this theory

It didn't fix it for me

@anaisbetts
Copy link
Member

anaisbetts commented Dec 6, 2021

@tomasfil I have a feeling you may have removed the template wrong. By Binding to ItemsControl, you get a default template that instantiates ViewModelViewHost. To "remove" the template, you need to replace it with something dumb like:

<ItemsControl.ItemTemplate>
  <DataTemplate><TextBlock Text="foo" /></DataTemplate>
</ItemsControl.ItemTemplate>

@tomasfil
Copy link
Contributor Author

tomasfil commented Dec 6, 2021

Ah yes, you mean ItemTemplate. But like this it won't auto resolve Views right? (I am not at PC now)

@anaisbetts
Copy link
Member

@tomasfil Correct - but we want to narrow the scope of what could be leaking, is the ViewModel holding onto something, or are we leaking Views (which will always leak ViewModels, since the View will always pin its own ViewModel)

Once we take the View out of the equation, it goes away, so we know that the thing we're leaking is TestViews

@tomasfil
Copy link
Contributor Author

tomasfil commented Dec 6, 2021

Can I do anything to help?

@luojunyuan
Copy link

Is this related to #1314 ? I may also meet the same situation.

image
image

The ViewModelViewHost hold my window which can not be released by GC after binding to ItemSource

@tomasfil
Copy link
Contributor Author

Seems like it of what I have read. It is app breaking for me since items in itemsource change a lot in my app, so the memory leak is huge.

That's kinda oof that the bug is there that long.

@ChrisPulman
Copy link
Member

ChrisPulman commented Dec 11, 2021

To test if ReactiveUI was the actual issue in the sample I removed ReactiveUI and just left DynamicData.
The XAML Bindings operate a lot slower, which slows the memory leak down but when left over time the result is the same.
https://github.com/ChrisPulman/ReactiveUI_MemoryLeakTest_Wpf
image

GitHub
Contribute to ChrisPulman/ReactiveUI_MemoryLeakTest_Wpf development by creating an account on GitHub.

@luojunyuan
Copy link

luojunyuan commented Dec 11, 2021

To test if ReactiveUI was the actual issue in the sample I removed ReactiveUI and just left DynamicData. The XAML Bindings operate a lot slower, which slows the memory leak down but when left over time the result is the same.

The modifications seem work fine to me. I clone it down and type dotnet run. There is the result ten minutes later. Memory is not getting bigger than bigger from task manager. The op's one suddenly get upper to 100mb.
image

@glennawatson
Copy link
Contributor

Not seeing the leak personally on dotMemory with Chris's DD only sample unfortunately. Testing the RxUI enabled one now.

image

@glennawatson
Copy link
Contributor

@tomasfil sample does leak, but the DD only version does not as far as I can tell. My experiments match @tomasfil

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 26, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants