内存与收集

时间:2014-01-14 18:32:56

标签: .net collections out-of-memory

我在.NET 4.0上,因此有2 GB的限制

这个get会在1/2时间内抛出一个内存不足的异常

public IEnumerable<FTSword7bitThesaurus> FTSwordsPlusSelected
{
    get
    {
        try
        {
            return FTSWords7bit.Select(w => new FTSword7bitThesaurus(this, w, selectedKeys.Contains(w.Key)));
        }

堆栈跟踪开始:
System.Collections.Generic.List'1_setCapacity(int32 value)

这是调用get

的代码
<ListView Grid.Row="4" Grid.Column="1" x:Name="lvFTSWordsMine"
                              ItemsSource="{Binding ElementName=lvThesarus, Path=SelectedItem.FTSwordsPlusSelected, Mode=OneWay}"
                              ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Hidden" VerticalContentAlignment="Stretch">

但令我困惑的是FTSwordsPlusSelected(应该)小于FTSWords7bit

这是FTSword7bitThesaurus中唯一的数据 一个bool和两个参考

public class FTSword7bitThesaurus : INotifyPropertyChanged
{
    bool selected = false;
    FTSword7bit fTSword;
    FTSthersarus fTSthersarus;

FTSWord7bit平均有20个字节的数据
FTSWords7bit采集尺寸为1200万FTSWord7bit
该集合尚未(但)抛出内存异常

我对那些我认为应该是较小物体的集合的记忆力不足了 我不能将整个集合描述为分析器balks

selectedKeys只是一个HashSet,从不超过10,000,通常少于200

因为首先创建了FTSWords7bit,你认为这仅仅是由于内存碎片造成的吗?

关于如何避免这种内存不足问题的任何想法?

FTSWords7bit被大量使用,我坚持认为 FTSword7bitThesaurus只是由一个管理员屏幕使用,我希望它们在退出该屏幕时被丢弃 大多数情况下,这个集合不到100万,但这是一个奇怪的数据集 如果我能稳定1200万我就可以了 我们甚至可以在内存不足的情况下生活,但它并没有给用户灌输信心 我们去.NET 4.5之前需要几个月的时间。

从接受的答案中得到 修复只是分页 很可能问题是连续的内存块不可用

public void NextPage()
{
    page++;
    NotifyPropertyChanged("FTSwordsPlusSelected");
}

public IEnumerable<FTSword7bitThesaurus> FTSwordsPlusSelected
{
    get
    {
        try
        {
            return FTSWords7bit.Skip(page * pageSize).Take(pageSize).Select(w => new FTSword7bitThesaurus(this, w, selectedKeys.Contains(w.Key)));
        }

1 个答案:

答案 0 :(得分:2)

问题在于,您的代码不仅需要一个非常大的连续内存块(通过List<>的数组),而且还必须为{{1}中的每个条目分配额外的内存。 }。我认为与ListView相关的开销非常小,并且导致问题。

有一些解决方案具有不同的复杂程度:

  • 数据虚拟化 - 此解决方案最适合您的用户。本质上,控件只会在内存中保留所需的行。您的用户当然无法说出来,因此这是最好,最复杂的解决方案。这个post有一个很好的例子。 (看起来像Google图片搜索)。
  • 控制分页 - 此解决方案看起来更像是网站选项。想想普通的谷歌,他们不会向你展示无限的结果,只是一个子集。然后,他们会让您选择下一页以获得更多结果。这可以通过ListView很好地完成,因为您可以为每个页面使用IEnumerable<>Skip()(假设您每页有25个条目,那么您将执行Take()) 。我发现这个解决方案更容易创建,但使用起来更多的负担。