【问题标题】:Free memory from viewModel from Ioc used in ContentControl从用于 ContentControl 的 Ioc 的 viewModel 释放内存
【发布时间】:2016-04-29 02:07:28
【问题描述】:

我目前正在使用 ContentControl 通过设置 VM 并使用这样的默认数据模板来显示我的视图:

<UserControl.Resources>
    <DataTemplate DataType="{x:Type vm:MyViewViewModel}">
        <views:MyView />
    </DataTemplate>
</UserControl.Resources>
<ContentControl Content="{Binding ContainerContent}"/>

这是我的容器内容:

public ViewModelBase ContainerContent
{
    get
    {
        return _containerContent;
    }
    set
    {
        if (_containerContent != null)
            _containerContent.Cleanup();

        _containerContent = value;
        RaisePropertyChanged("ContainerContent");
    }
}

我目前使用 SimpleIoc 通过 serviceLocator 加载 ViewModel:

ContainerContent = ServiceLocator.Current.GetInstance<MyViewViewModel>();

这很好用,可以正确显示我的视图,并将 viewModel 分配给内容。

不幸的是,当我想从我的 ContentControl 中删除视图(和视图模型)时,由于 ViewModel、View 和 SimpleIoc 之间的释放顺序,我的内存仍在使用。视图有一段时间引用它(我认为这个时间是由于容器上 RaisePropertyCHange 之后的绑定)

我目前使用一种方法来删除内容:

 public void QuitCurrentContainerViewModel<T>() where T : class
        {
            ContainerContent = null;
            Task.Factory.StartNew(() =>
            {
                if (/*!*/SimpleIoc.Default.ContainsCreated<T>())
                {
                    SimpleIoc.Default.Unregister<T>();
                }
                DispatcherHelper.RunAsync(() =>
                {
                    MessageBox.Show("Do GC now");
                    GC.Collect();

                }, DispatcherPriority.ApplicationIdle);
            });
        }

(使用调度器和优先级是一个测试)

如果我有时调用它,我的内存会被正确释放,但并非总是如此。

在任何情况下,例如,如果我从快捷方式强制执行 GC.Collect,我的内存都会得到正确管理。

在我的情况下释放内存的好方法是什么?

谢谢!

编辑:我的错,它适用于该代码(在我的 QuitCurrentContainerViewModel 方法中,我正在使用此检查:

if (!SimpleIoc.Default.ContainsCreated<T>())

但我需要这个:

if (SimpleIoc.Default.ContainsCreated<T>())

这样看来效果不错。

【问题讨论】:

    标签: c# wpf mvvm mvvm-light ioc-container


    【解决方案1】:

    在我的情况下释放内存的好方法是什么?

    对每个对象使用IDisposable 模式,并在泛型类型说明符中要求它。这样可以直接调用顶级实体,随后可以清除所有与接口相关的子引用。

    记住具有订阅的实例,尽管该实例没有在代码中直接引用,但如果它们有任何活动的订阅,它们将变为固定并保持活动状态;阻止垃圾收集器。

    必须先取消链接所有订阅,然后才能对实例进行垃圾回收。

    如果我有时调用它,我的内存会被正确释放,但并非总是如此。

    您在查看应用程序的私有字节吗?因为操作系统报告了一个完整的总数,如果操作系统没有受到压力,它不会占用内存,让应用程序可以呼吸。私有字节将在全部分配的总数中上下波动。

    因此,您可能正在监控错误的值。

    【讨论】:

    • 感谢您的回复。我已经尝试过实施 Idisposable 但没有成功。它认为 dispose 方法没有被调用,因为视图在刷新之前“阻塞”了实例。关于内存消耗,我使用带有私有字节的进程资源管理器性能视图。
    【解决方案2】:

    这是我清理的代码,没有无用的调用

        public ViewModelBase ContainerContent
                {
                    get
                    {
                        return _containerContent;
                    }
                    set
                    {
                        if (_containerContent != null)
                            _containerContent.Cleanup();
    
                        _containerContent = value;
                        RaisePropertyChanged("ContainerContent");
                    }
                }
    
                public void QuitCurrentContainerViewModel<T>() where T : class
                {
                    ContainerContent = null;
                    Task.Factory.StartNew(() =>
                    {
                        if (SimpleIoc.Default.ContainsCreated<T>())
                        {
                            SimpleIoc.Default.Unregister<T>();
                            GC.Collect();
                        }
    //TODO: Do navigation or change of content    
                    });
                }
    

    这里是我对 ContentContainer 的加载

       Task.Factory.StartNew(() =>
                {
                    if (!SimpleIoc.Default.ContainsCreated<MyViewModel>())
                        SimpleIoc.Default.Register<MyViewModel>();
                    ContainerViewModel.ContainerContent = SimpleIoc.Default.GetInstance<MyViewModel>();
                });
    

    如果有人有更好的方法来解决这个内存管理,我完全开放。

    【讨论】:

      猜你喜欢
      • 2021-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-10
      • 1970-01-01
      • 2015-10-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多