Question

I have problem with increasing memory. I use MEF in caliburn.micro on creation new screen - WPF window.

View model of screen/view look like this:

[Export(typeof(IChatViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class ChatViewModel : Screen, IChatViewModel
    {}

On creation I use ExportFactory, controler is here:

public interface IViewModelsControler
{
    ExportLifetimeContext<IChatViewModel> CreatChatViewModel();
}

[Export(typeof(IViewModelsControler))]
public class ViewModelsControler : IViewModelsControler
{
    [Import]
    public ExportFactory<IChatViewModel> ChatViewFactory { get; set; }

    public ExportLifetimeContext<IChatViewModel> CreatChatViewModel()
    {
        return ChatViewFactory.CreateExport();
    }
}

I use ViewModelsControler class in ChatScreenManager class. This class Open/Remove chat screen.

Here is it:

  [Export(typeof(IChatScreenManager))]
    public class ChatScreenManager : IChatScreenManager
    {
        private IWindowManager _windowManager;

        [Import]
        public IViewModelsControler ViewModelControler { get; set; }

        [ImportingConstructor]
        public ChatScreenManager(IWindowManager windowManager)
        {
            _windowManager = windowManager;
            ActiveChatScreens = new Dictionary<string, ExportLifetimeContext<IChatViewModel>>();
        }

        //store active screen
        public Dictionary<string, ExportLifetimeContext<IChatViewModel>> ActiveChatScreens { get; set; }


        public void OpenChatScreen(DetailData oponent, string avatarNick, BitmapImage avatarImage)
        {
            if (!ActiveChatScreens.ContainsKey(oponent.Info.Nick))
            {
                //create new chat screen with view model controler
                ExportLifetimeContext<IChatViewModel> chatScreen = ViewModelControler.CreatChatViewModel();

                //show
                _windowManager.Show(chatScreen.Value);

                //add ref to the dic
                ActiveChatScreens.Add(oponent.Info.Nick, chatScreen);
            }
        }

        public void RemoveChatScreen(string clossingScreen)
        {

            MessageBox.Show(GC.GetTotalMemory(true).ToString());

            ActiveChatScreens[clossingScreen].Dispose();

            ActiveChatScreens.Remove(clossingScreen);

            GC.Collect();
            GC.SuppressFinalize(this);

            MessageBox.Show(GC.GetTotalMemory(true).ToString());
        }
    }

And my problem is:

  • I call OpneChatScreen method from ChatScreenManager it open new WPF window
  • Add reference on this window to the dictionary.
  • When I am closing window I call RemoveChatScreen.

In RemoveChaScreen:

  • I get total memory, for example is it 37,000K
  • Then I call Dipose method on ExportLifetimeContext chatScreen
  • Force GC
  • And get total memory, for example is it 39,000K

Memory usage is stil increasing. I hope if I call Dispose method on object ChatViewModel and also ChatView object these object are destroyed.

Was it helpful?

Solution

Do not force GC! Also, the Dispose() method should follow removal from your collection.

public void RemoveChatScreen(string closingScreen)
{
    MessageBox.Show(GC.GetTotalMemory(true).ToString());

    IChatViewModel chatWindow = ActiveChatScreens[closingScreen]

    // remove from collection - GC may pass over object referenced in collection
    // until next pass, or 3rd pass...who knows, it's indeterminate
    ActiveChatScreens.Remove(closingScreen);

    // all clean up should be performed within Dispose method
    chatWindow.Dispose(); 

    //GC.Collect();
    //GC.SuppressFinalize(this);

    MessageBox.Show(GC.GetTotalMemory(true).ToString());
}

Forcing garbage collection is not recommended. There are ways to work with GC, however, and that is typically done in the Dispose() method of the disposable class. Your derived ChatView object should be defined something like:

class ChatView : IChatViewModel, IDisposable
{  }

ChatView requires a Dispose() method be implemented. There is a pattern to follow (from MSDN) when creating disposable classes:

// Design pattern for a base class.
public class ChatView : IChatViewModel, IDisposable
{
    private bool disposed = false;

    //Implement IDisposable.
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Free other state (managed objects).
            }
            // Free your own state (unmanaged objects).
            // Set large fields to null.
            disposed = true;
        }
    }

    // Use C# destructor syntax for finalization code.
    ~ChatView()
    {
        // Simply call Dispose(false).
        Dispose (false);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top