Disposing ViewModel

Jul 25, 2010 at 1:44 AM

Hi Sacha, I'm playing with CinchV2 for few days along with the ImageLoader demo. I'm wondering how to handle closing resources. I tried to override OnDispose() (and put few breakpoints), but it is never been called. Am I missing something? Can you please guide me on properly calling OnDispose on each ViewModels? Thanks.

BTW, CinchV2 looks promising.

Coordinator
Jul 25, 2010 at 2:29 PM

Oh it definitely does call dispose on the IMageLoaderView, I did absolutely loads of tests on that. I think the problem is that the GC does not kick in until it needs to, it non-deterministic, so I don't think you can really rely on it. I think to test it you can put a destructor in IMageLoaderView and put a private field like 

byte[] myMemory = new byte[100 * 1024 * 1024];

That is what I did during testing, and I did see the View being GCd, with the demo app for Cinch V2

Nov 29, 2010 at 1:54 AM

Hey Sacha,

First off I would like to say how much I enjoy using Cinch, it's awesome.

I've been using CinchV1 for over a year in a large WPF project, and now looking into converting to CinchV2. 

I have also been playing with the WPF demo, and can't see to get the viewmodels to dispose.

Each time I click the "Home Page" in the AboutViewModel which opens a popup of AboutViewLinkRequestedPopupViewModel, the memory footprint increases (obviously) however, upon closing, the resources never seem to be reclaimed.

If say, you open 10 or 15 popup windows one after each other, the memory usage for me is up at around 200,000K (about 10,000K per window open)

There is that really useful destructor in the ViewModelBase which prints out when the ViewModel has been finalised, but that only seems to happen when the entire app is closed, then there is a stream of the 10 - 15 popupwindow ViewModels being finalised.

Am I doing something wrong or missing something?

Thanks.

Coordinator
Dec 3, 2010 at 5:46 AM

See my answer to below

Coordinator
Dec 3, 2010 at 5:52 AM

AskGl/Sagoo33

Garbage collection is non deterministic and only kicks in when it needs to do so. There are things called generations (.NET has 3) and there is also a compaction cycle, but you are not in control of this, so what you report does not surprise me at all.

To illustrate this I have altered my own demo code for CinchV2 using the AboutView and the ImageLoaderView and made them eat up much more memory that they actually need, by declaring an large array in the view. Now even with this I was able to open up about 15  different ImageLoaderViews before the GC kicked in, and call the View descructor, as can be seen in the following image

 

http://dl.dropbox.com/u/2600965/CinchDescrutor.png

 

Which means that the GC is doing what is should, basically when it runs out of heap space it trying to collect some space...For me all is working as expected

 

Dec 6, 2010 at 4:19 AM

Ah right!

Thanks Sacha, that makes sense, I wasn't ever using enough memory to actually see the GC kick in.

Thanks again!

Coordinator
Dec 6, 2010 at 5:23 AM

sagoo yes that is what I believe to me true

Dec 29, 2010 at 8:19 AM
Edited Dec 29, 2010 at 10:00 AM

You can trigger the GC with:

GC.Collect();

@sacha
maybe you could add a call to Dispose in your tabcontrol when a IDisposable item is removed. Run into a issue that the view is not garbage collected because i used a webbrowser in it.

 

Dec 29, 2010 at 11:49 AM
Edited Dec 30, 2010 at 8:22 AM

Hmm it seems that the view get gc but the vm not, even they have the partcreationpolicy on nonshared. But i think thats related to the mechanism are used in mefedmvvm.

http://mefedmvvm.codeplex.com/Thread/View.aspx?ThreadId=228781

One work around to let the vm be gc would be to remove the IDisposable interface of the Cinch.ViewModelBase and setting the PartCreationPolicy attribut to your vm to NonShared.

[PartCreationPolicy(System.ComponentModel.Composition.CreationPolicy.NonShared)]

The dialogs shown by the WPFUIVisualizerService doesn't get gc, too. First when the DataContext of the window will be set to null, so no reference to the vm exist anymore and it can be collected too, or another dialog will be shown, the window will be able to gc. Thats because the service adds a event handler on the vm which reference to the view.

Coordinator
Dec 31, 2010 at 5:11 PM
Edited Dec 31, 2010 at 5:18 PM

mmm crap, yeah I think this is something I am going to have to change. i'll look into this, perhaps changing to ICleansable or something else that MEF does not care about. ViewModels are already NonShared.

 

So what I think I am going to do is

 

1. Make new interface in ViewModelBase instead of IDisposable

2. Make sure WPFUIVisualiser uses weakevents

3. The special TabControlEx can not tell its View to Dispose() as its all done via DataTemplate etc etc., so you never have a handle to the actual View that is done via a lookup mechanism/attached DP etc etc

Coordinator
Jan 1, 2011 at 8:10 AM

I have now fixed all this I feel. See latest release and the notes associated with it.

Popups/ChildWindows

I have tested it for SL/WPF and see all popups being disposed (when the GC sees fit though, so may have to open a few popups in order for GC to actually collect)

MEF and IDisposable

You were correct about my being dumb implementing IDisposable, I have swapped that for new CinchV2 interface called ICinchDisposable, which you should call when your Views deconstructor is called. Again Views deconstructor is called when GC sees fit

Jan 3, 2011 at 7:06 AM
sachabarber wrote:

3. The special TabControlEx can not tell its View to Dispose() as its all done via DataTemplate etc etc., so you never have a handle to the actual View that is done via a lookup mechanism/attached DP etc etc

I handled that by adding a dispose event on the WorkspaceData and adding a eventhandler OnViewCreatorChanged in NavProps if the view implements IDisposable.

if (dataAwareView is IDisposable) {
    viewNavData.Disposed += delegate {
         ((IDisposable)dataAwareView).Dispose();
    };
}

So the TabcontrolEx can call Dispose on the WorkspaceData which calls Dispose on the view.

And as i see your solution works great. Thx for your fast response :)


Coordinator
Jan 3, 2011 at 7:12 AM

HelmuE

Yes I can see that your approach would work too. Though I think I will stick to what I have done for now, and possibly add this to the list of things to do as some point too. Any chance you could post the full set of changes that you made to support the Dispose in WorkSpaceData, I can not see who would call Disposed event on WorkSpaceData. Could you post the code, and I'll include that too next time. Interesting enough I am writing a CinchV2 article where I am showing how well CinchV2 works with the new PRISM (Mef version) drop, 4.0 I think. It works like a charm, and due to the fact that PRISM regions does not rely on DataTemplate to create content, you do not even need my special TabControlEx. Sample nearly done, just need to make custom RegionAdaptor and do threading helper, then I'll write the article up.

Coordinator
Jan 3, 2011 at 7:14 AM

Actually I do see what you mean now, but if you could email me modified files and post them in this forum (to help others), I will look to include them in later release on Cinch.

My email is sacha[DOT]barber[AT]gmail[DOT]com

Jan 3, 2011 at 8:23 AM

Added to the patch category with id: 7947

http://cinch.codeplex.com/SourceControl/PatchList.aspx

Coordinator
Jan 3, 2011 at 9:18 AM

Thanks Helmut I'll look into this. I sent you an email, would be curious to here what you say about that before I add this. As I think my fix also works right?