【问题标题】:MemoryManagement for ObservableCollections in .Net.Net 中 ObservableCollections 的内存管理
【发布时间】:2014-10-10 17:31:46
【问题描述】:

我正在开发一个 WPF 应用程序,其中我正在使用 CustomObject 的 ObservableCollection

public ObservableCollection<ProjectsToShow> Projects{get;set;}

ProjectsToShow 类的定义

public class ProjectsToShow 
{
    public ProjectsToShow()
    {
        Wells = new ObservableCollection<WellsToShow>();
    }

    public Project ProjectObject { get; set; }

    ObservableCollection<WellsToShow> _wells;

    public ObservableCollection<WellsToShow> Wells{get;set;}
}

该类为 WellsToShow 初始化一个集合,其定义为

 public class WellsToShow 
{
    public WellsToShow()
    {
        Datasets = new ObservableCollection<DatasetsToShow>();
    }

    public Well WellObject { get; set; }

    ObservableCollection<DatasetsToShow> _datasets;
    public ObservableCollection<DatasetsToShow> Datasets
    {
        get { return _datasets; }
        set
        {
            _datasets = value;
            NotifyPropertyChanged("Datasets");
        }
    }
}

还有一个像这样的级别。

现在我正在使用内存分析器分析我的应用程序,它会不断将集合中的对象添加到内存中。我期待着那个电话

Projects.Clear();

将从内存中释放所有对象,但它不会那样工作。即使我尝试将项目设置为空,但即使这样也没有用。 WellsToShow 和 DatasetToShow 的对象仍然保留在内存中。因此,出于测试目的,我尝试使用此代码

foreach(var project in MainViewModel.Projects)
        {
            foreach(var well in project.Wells)
            {
                well.Datasets.Clear();                    
            }
            project.Wells.Clear();
        }
        MainViewModel.Projects.Clear();

根据内存分析器,它们不再在内存中。作为记录,每次我运行分析器时,它都会先运行 GC.Collect,然后再进行分析。

请解释一下这个东西是如何工作的。如果这是清除集合的正确方法,那么我需要在所有项目中运行并修复这个东西。

更新1,将此集合绑定到视图

我正在将我的 Project 属性绑定到 TreeView 控件,并在对其进行探查时进行调查。此控件保留了我的收藏,我认为清除项目源收藏应该可以完成这项工作,但这里不是这种情况。

  <TreeView VirtualizingStackPanel.IsVirtualizing="False"                                      ItemsSource="{Binding Projects}">
           <TreeView.Resources>
                                <HierarchicalDataTemplate DataType="{x:Type bll:ProjectsToShow}" ItemsSource="{Binding Wells}">
                                    <TextBlock HorizontalAlignment="Stretch" Text="{Binding ProjectName}" x:Name="TextBlockProject" Tag="{Binding DataContext,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}">
                                        <TextBlock.ContextMenu>
                                            <ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}"  >
                                                <MenuItem 
                                                          Command="{Binding FileEditProjectCommand}">
                                                    <MenuItem.Header>
                                                        <TextBlock Text="{DynamicResource EditProject}"/>
                                                    </MenuItem.Header>
                                                </MenuItem>

                                                <MenuItem Command="{Binding FileDeleteProjectCommand}">
                                                    <MenuItem.Header>
                                                        <TextBlock Text="{DynamicResource DeleteProject}"/>
                                                    </MenuItem.Header>
                                                </MenuItem>
                                            </ContextMenu>
                                        </TextBlock.ContextMenu>
                                    </TextBlock>
                                </HierarchicalDataTemplate>
                                <HierarchicalDataTemplate DataType="{x:Type bll:WellsToShow}" ItemsSource="{Binding Datasets}">
                                    <TextBlock HorizontalAlignment="Stretch" Text="{Binding WellName}" Tag="{Binding DataContext,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}">
                                        <TextBlock.ContextMenu>
                                            <ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
                                                <MenuItem Command="{Binding FileEditWellCommand}">
                                                    <MenuItem.Header>
                                                        <TextBlock Text="{DynamicResource EditWell}"/>
                                                    </MenuItem.Header>
                                                </MenuItem>
                                                <MenuItem  Command="{Binding FileDeleteWellCommand}">
                                                    <MenuItem.Header>
                                                        <TextBlock Text="{DynamicResource DeleteWell}"></TextBlock>
                                                    </MenuItem.Header>
                                                </MenuItem>
                                            </ContextMenu>
                                        </TextBlock.ContextMenu>
                                    </TextBlock>
                                </HierarchicalDataTemplate>

附上更新 2 截图

【问题讨论】:

  • 如果您正在使用分析器,请检查哪些对象导致了井和数据集被扎根。它可能是一个绑定到您的视图模型的视图,使它们保持活动状态。
  • 您能在 View 中显示绑定吗?
  • @mikez 我已经更新了这个问题。请立即调查。
  • @MegaMind - Profiler 还会告诉您根对象的详细信息。查看哪些对象保留了您的引用。
  • @RohitVats MainWindow->TreeView->System.Windows.DataBinding->DatasetsToShow

标签: c# wpf garbage-collection observablecollection


【解决方案1】:

如果可视对象对应于(曾经)在集合中的对象,则这些可视对象将在其各自的 DataContexts 中保留这些引用。确保仅在对象已直观清除后运行内存配置文件。

我还推荐 Snoop 用于任何 WPF 调试工作,因为这可能能够显示您的对象以及引用它们的内容。

【讨论】:

    猜你喜欢
    • 2011-11-11
    • 2012-01-18
    • 1970-01-01
    • 2010-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-31
    相关资源
    最近更新 更多