【问题标题】:Export with MEF in Caliburn.Micro - Increasing memory problem在 Caliburn.Micro 中使用 MEF 导出 - 增加内存问题
【发布时间】:2011-01-05 14:02:55
【问题描述】:

我在增加内存时遇到问题。我在 caliburn.micro 中使用 MEF 创建新屏幕 - WPF 窗口。

屏幕/视图的视图模型如下所示:

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

在创建时我使用 ExportFactory,控制器在这里:

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();
    }
}

我在 ChatScreenManager 类中使用 ViewModelsControler 类。此类打开/删除聊天屏幕。

这里是:

  [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());
        }
    }

我的问题是:

  • 我从 ChatScreenManager 调用 OpneChatScreen 方法打开新的 WPF 窗口
  • 将此窗口上的引用添加到字典。
  • 当我关闭窗口时,我调用 RemoveChatScreen。

在 RemoveChaScreen 中:

  • 我得到总内存,例如是 37,000K
  • 然后我在 ExportLifetimeContext chatScreen 上调用 Dipose 方法
  • 强制 GC
  • 并获取总内存,例如是 39,000K

内存使用量仍在增加。我希望如果我在对象 ChatViewModel 和 ChatView 对象上调用 Dispose 方法,这些对象都会被销毁。

【问题讨论】:

  • 仅供参考,使用 [c#] 或 [net] 标签来识别您的问题,以便可以正确格式化代码示例。 ;)

标签: c# ioc-container mef caliburn.micro


【解决方案1】:

不要强制 GC!此外,Dispose() 方法应从您的收藏中删除。

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());
}

不推荐强制垃圾回收。但是,有一些方法可以使用 GC,这通常在一次性类的 Dispose() 方法中完成。您的派生 ChatView 对象应定义为:

class ChatView : IChatViewModel, IDisposable
{  }

ChatView 需要实现 Dispose() 方法。创建一次性类时有一个pattern to follow(来自 MSDN)

// 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);
    }
}

【讨论】:

  • 感谢您的建议,我现在的问题是如何将 ViewModel 类的 Dispose 方法与 WPF 窗口上的“View Dispose Method”连接起来(View 是 WPF 窗口)。例如,我在 ViewModel 类上调用 Dispose 方法,它还在 View-WPF 窗口对象上调用 Dipose 方法。
  • 例如我在 ViewModel 上调用 Dispose 方法,它也调用了destroy View,即 WPF Window。
  • 我以为stackoverflow.com/questions/4597317/… 已经为你解答了。
  • 对不起,你不明白我的意思。你对 MVVM、caliburn.micro 有所了解吗?因此,您可以使用 caliburn 创建简单的 MVVM WPF 应用程序。为此视图创建视图(WPF 窗口)和视图模型。使用 MEF 导出此视图模型类。并尝试从视图模型类中销毁视图对象。您可以在视图模型类上实现 IDisposable 接口,但这并不能解决这个问题。因为您只在视图模型类上将类型销毁为位图。
  • @jminarik - 不要忘记Dispose 的用途,用于安全处置 非托管 对象并将处置链接到其他托管对象。您可以在任何您喜欢的项目上调用Dispose 并清理它已使用的非托管资源,但您仍然需要等待 GC 来清理。你也不应该强迫这个。如果您真的担心这种方式的内存占用,我真的会看看您的应用程序究竟在做什么来导致您认为内存问题....
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
相关资源
最近更新 更多