0

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.

IAbstract
  • 19,551
  • 15
  • 98
  • 146
  • FYI, use the [c#] or [net] tags to identify your questions so code samples can be formatted properly. ;) – IAbstract Jan 05 '11 at 14:51

1 Answers1

2

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);
    }
}
IAbstract
  • 19,551
  • 15
  • 98
  • 146
  • Thank for advice, my problem is now how connect Dispose method from ViewModel class with "View Dispose Method" on WPF window (View is WPF window). For example I call Dispose method on ViewModel class and it also call Dipose method on View- WPF window object. –  Jan 05 '11 at 15:00
  • For example I call Dispose Method on ViewModel and it also call destroy View, wich is WPF Window. –  Jan 05 '11 at 15:01
  • I thought http://stackoverflow.com/questions/4597317/problem-with-mef-exportfactoryt-call-dispose-method/4599836#4599836 answered it for you. – IAbstract Jan 05 '11 at 15:04
  • Sorry but you do not understand me. Do you know something about MVVM, caliburn.micro? So you can create simple MVVM WPF app with caliburn. Create view (WPF Window) and view model for this view. Export this view model class with MEF. And try destroy object of view from view model class. You can implement IDisposable interface on your view model class but this doesn’t solve this problem. Because you only destroy type as bitmap on view model class. –  Jan 05 '11 at 15:42
  • @jminarik - Don't forget what `Dispose` is meant for, for the safe disposing of *unmanaged* objects and chaining disposal to other managed objects. You can call `Dispose` on an item all you like and clean up and unmanaged resources it has used, but you've still got to wait for the GC to get round to clearing up. You also shouldn't force this. If you're really concerned about memory footprint this way I would really look at what exactly your application is doing to cause what you consider memory issues.... – Matthew Abbott Jan 05 '11 at 17:38