Resolved Preventing any duplication of views/view models

MattNorman

Well-known member
Joined
May 22, 2021
Messages
98
Programming Experience
1-3
I have noticed that my memory usage keeps increasing when switching views.

This is expected at the moment up until a point where each view has been loaded once.

The issue I have is if I switch to my 'Dashboard' view, switch to another view and then back to the dashboard view, it doesn't appear that the previous view is cleared from memory.

I tried setting up a dictionary that holds a reference to all view models and if a view is loaded a second time, it will set that reference to a new instance and assign it as the data context. I'm not sure this is working though as I still see the memory usage climbing.

I know I am probably going about this the complete wrong way so would appreciate any advice.

I essentially have a main window that contains all of the menu along with a content control. The content control is bound to a property that holds an instance of the view that is to be displayed.

How should I go about making sure everything is fully released whenever I change the view that is displayed in the content control?

Regards
Matt
 
Solution
That's the way .NET works. It is basically more efficient to simply keep allocating new memory as it is required and then just clean up large chunks of memory from time to time or if it is specifically needed. As an application developer, it's not your job to think about memory specifically. You just need to think about objects. If you create an object that can be disposed, dispose it when you're done with it. If you are not going to use an object any longer, make sure that there are no references to it maintained for long periods of time in your code. If you do those two things then you will pretty much never have to worry about memory usage at all.

Disposing objects is generally very easy. In most cases, you will create an object and...
Whatever you do, do not use the anti-pattern of forcing garbage collection.
 
I tried setting up a dictionary that holds a reference to all view models and if a view is loaded a second time, it will set that reference to a new instance and assign it as the data context.
My reading of that is that you are caching the view models, but still creating new views. Why would you expect creating a new view would not use more memory?
 
That's the way .NET works. It is basically more efficient to simply keep allocating new memory as it is required and then just clean up large chunks of memory from time to time or if it is specifically needed. As an application developer, it's not your job to think about memory specifically. You just need to think about objects. If you create an object that can be disposed, dispose it when you're done with it. If you are not going to use an object any longer, make sure that there are no references to it maintained for long periods of time in your code. If you do those two things then you will pretty much never have to worry about memory usage at all.

Disposing objects is generally very easy. In most cases, you will create an object and use right there, then not use it any further. In such cases, a using statement will create the object, allow you to use it within the block and then dispose it implicitly at the end. If you use an object outside the method that it is created in, then you have to do a bit more work to track it and dispose it explicitly when you're done with in.

Making sure that there are no remaining references to unused objects is also generally fairly easy. If you create an object and assign it to a local variable, that reference is removed as soon as that variable falls out of scope. It's only when you assign objects to fields and those fields remain in scope after you finish using the object that you need to explicitly set such fields to null and remove the reference to the object.

If you do those two things then the system will clean up the memory allocated automatically when the garbage collector runs and it will be able to do so as quickly as possible. That's all you need to care about.
 
Solution
BTW, often times you'll find that, in a GUI app, if you have a form/window visible and you minimise it, your app's memory usage will drop considerably. That's because the GC will run while your app is minimised. That same GC would occur while your app was in use but it tends to be put off because it may cause a moment of unresponsiveness if it happens while the user is doing something. The GC tries to cause as little disruption for the user as possible and millions of .NET users the world over have no problem with it. Stop trying to fix what isn't broken.
 
My reading of that is that you are caching the view models, but still creating new views. Why would you expect creating a new view would not use more memory?
Good point, here is what I am doing for the views:

Property for content control binding:
C#:
/// <summary>
/// Used to store an instance of the current view being displayed in the content control.
/// </summary>
public object CurrentView { get; set; }

Method for selecting dashboard view:
C#:
/// <summary>
/// Triggered when the user selects the dashboard menu item.
/// </summary>
public void DashboardSelect(object param)
{
    string methodName = "DashboardSelect()";

    try
    {
        //Update menu item states.
        MenuStateManager.ChangeSelection(MenuItems.Dashboard);

        //Display view.
        DisposeOfCurrentViewModel();
        CurrentView = new DashboardView2();
    }
    catch (Exception ex)
    {
        DataManagerLogs.WriteToErrorLog($"{classNamespace}.{methodName}", ex.ToString(), "");
    }
}

I assumed that when setting the property to a different view object the previously assigned object would be cleared from memory. Is that not the case?

The DisposeOfCurrentViewModel(); method is something I added to test that is stopping timers on the dashboard view model and un-registering any events. This was suggested in a few posts I found.
 
The DisposeOfCurrentViewModel(); method is something I added to test that is stopping timers on the dashboard view model and un-registering any events. This was suggested in a few posts I found.
If you use += in code to register an event handler then you should definitely use -= when you're done handling that event. Registering an event handler creates a delegate and that creates a reference, so you need to unregister the event handler to remove the reference.
 
If you use += in code to register an event handler then you should definitely use -= when you're done handling that event. Registering an event handler creates a delegate and that creates a reference, so you need to unregister the event handler to remove the reference.
Thanks.

In the case of the fields in my ViewModels that are used for binding. Should I be manually setting all of these to null once I am done with the view model?
 
Thanks.

In the case of the fields in my ViewModels that are used for binding. Should I be manually setting all of these to null once I am done with the view model?
They will be cleaned up regardless but it may take an extra step. If they refer to objects that occupy a lot of memory themselves then doing so may be worthwhile, to get that memory released a little earlier. An example might be a huge DataTable. A string field that contains "Hello World" would be pointless to clear.
 
Back
Top Bottom