.Net列表和最大元素数

问题描述:

因此,我正在开发一个仅附加的64位列表和字典,并且我遇到了内存错误。我想我会在某些时候,但不是在64 MB。我发现有些意外,并且很好奇,如果有人能够向我解释为什么它在64 MB时遇到问题。.Net列表和最大元素数

我对我的新List类的测试只是试图创建8 GB的bools并加载到列表中。我想他们每个人只会吸1个位,所以我会得到一些很好的度量/精度来测试我的程序。

下面是来自VS输出:

-  this {OrganicCodeDesigner.DynamicList64Tail<bool>} OrganicCodeDesigner.DynamicList64Tail<bool> 
     Count 536870912 ulong 
-  data Count = 536870912 System.Collections.Generic.List<bool> 
-  base {"Exception of type 'System.OutOfMemoryException' was thrown."} System.SystemException {System.OutOfMemoryException} 
-  base {"Exception of type 'System.OutOfMemoryException' was thrown."} System.Exception {System.OutOfMemoryException} 
+  Data {System.Collections.ListDictionaryInternal} System.Collections.IDictionary {System.Collections.ListDictionaryInternal} 
     HelpLink null string 
+  InnerException null System.Exception 
     Message "Exception of type 'System.OutOfMemoryException' was thrown." string 
     Source "mscorlib" string 
     StackTrace " at System.Collections.Generic.Mscorlib_CollectionDebugView`1.get_Items()" string 
+  TargetSite {T[] get_Items()} System.Reflection.MethodBase {System.Reflection.RuntimeMethodInfo} 
+  Static members  
+  Non-Public members  
-  Raw View   
     Capacity 536870912 int 
     Count 536870912 int 
-  Static members  
+  Non-Public members  
-  Non-Public members  
+  _items {bool[536870912]} bool[] 
     _size 536870912 int 
     _syncRoot null object 
     _version 536870912 int 
     System.Collections.Generic.ICollection<T>.IsReadOnly false bool 
     System.Collections.ICollection.IsSynchronized false bool 
     System.Collections.ICollection.SyncRoot {object} object 
     System.Collections.IList.IsFixedSize false bool 
     System.Collections.IList.IsReadOnly false bool 
     item false bool 
-  Type variables  
     T bool bool 

,这里是我目前工作的类:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace OrganicCodeDesigner 
{ 
    public class DynamicList64Tail<T> : iList64<T> 
    { 
     private List<T> data; 

     public DynamicList64Tail() 
     { 
      data = new List<T>(); 
     } 


     public void Add(T item) 
     { 
      data.Add(item); 
     }  

     public void Clear() 
     { 
      data.Clear(); 
     } 

     public bool Contains(T item) 
     { 
      return data.Contains(item); 
     } 

     public ulong? IndexOf(T item) 
     { 
      if(this.data.Contains(item)) { 
       return (ulong)data.IndexOf(item); 
      } 
      return null; 
     } 

     public T this[ulong index] 
     { 
      get 
      { 
       return data[(int)(index)]; 
      } 
      set 
      { 
       data[(int)(index)] = value; 
      } 
     } 


     public ulong Count 
     { 
      get { return (ulong)data.Count; } 
     } 

    } 
} 


using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Collections; 

namespace OrganicCodeDesigner 
{ 
    // @todo: Create IList64, with 64-bit longs in mind. 
    // @todo: Create BigIntegerList, which may supersede this one. 
    public class DynamicList64<T> : iList64<T> 
    { 
     private List<iList64<T>> data; 

     private ulong count = 0; 
     private ulong depth = 0; 

     public DynamicList64() 
     { 
      data = new List<iList64<T>>() { new DynamicList64Tail<T>()}; 
      count = 0; 
     } 

     public DynamicList64(ulong depth) 
     { 
      this.depth = depth; 
      if (depth == 0) 
      { 
       data = new List<iList64<T>>() { new DynamicList64Tail<T>() }; 
      } 
      else 
      { 
       depth -= 1; 
       data = new List<iList64<T>>() { new DynamicList64<T>(depth) }; 
      } 
     } 

     internal DynamicList64(List<iList64<T>> data, ulong depth) 
     { 

      this.data = data; 
      this.depth = depth; 
      this.count = Int32.MaxValue; 


     } 

     public void Add(T item) 
     { 
      if (data.Count >= Int32.MaxValue) 
      { 
       //@todo: Do switch operation, whereby this {depth, List l} becomes this {depth + 1, List.Add(List l), count = 1}, and the new object becomes {depth, List l, count = max} 
       DynamicList64<T> newDynamicList64 = new DynamicList64<T>(this.data, this.depth); 
       this.data = new List<iList64<T>>() { newDynamicList64 }; 
       this.count = 0; 
       this.depth += 1; 
      } 

      if(data[data.Count-1].Count >= Int32.MaxValue) { 
       if (depth == 0) 
       { 
        data.Add(new DynamicList64Tail<T>()); 
       } 
       else 
       { 
        data.Add(new DynamicList64<T>(depth - 1)); 
       } 
      } 

      data[data.Count - 1].Add(item); 
      count++; 
     } 



     public void Clear() 
     { 
      data.Clear(); 
      data = new List<iList64<T>>() { new DynamicList64Tail<T>() }; 
      count = 0; 
      depth = 0; 
     } 

     public bool Contains(T item) 
     { 
      foreach(iList64<T> l in data) { 
       if(l.Contains(item)) { 
        return true; 
       } 
      } 
      return false; 
     } 

     public ulong? IndexOf(T item) 
     { 
      for (int i = 0; i < data.Count; i++) 
      { 
       if (data[i].Contains(item)) 
       { 
        return (ulong)(((ulong)i * (ulong)(Int32.MaxValue)) + data[i].IndexOf(item).Value); 
       } 
      } 

      return null;   
     } 

     public T this[ulong index] 
     { 
      get 
      { 
       return data[(int)(index/Int32.MaxValue)][index % Int32.MaxValue]; 
      } 
      set 
      { 
       data[(int)(index/Int32.MaxValue)][index % Int32.MaxValue] = value; 
      } 
     } 


     public ulong Count 
     { 
      get { return this.count; } 
     } 

    } 
} 


using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace OrganicCodeDesigner 
{ 
    public interface iList64<T> 
    { 
     void Add(T item); 
     void Clear(); 
     bool Contains(T item); 
     ulong? IndexOf(T item); 
     T this[ulong index] { get; set;} 
     ulong Count { get; } 

    } 
} 

和测试程序的代码:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using OrganicCodeDesigner; 

namespace OrganicCodeDesignerListDictionaryTest 
{ 
    public partial class MainForm : Form 
    { 
     public MainForm() 
     { 
      InitializeComponent(); 
     } 

     private void Button_TestList_Click(object sender, EventArgs e) 
     { 
      DynamicList64<bool> newList = new DynamicList64<bool>(); 
      newList.Add(true); 
      newList.Add(false); 

      bool b = true; 
      for (ulong i = 0; i < 68719476736; i++) 
      { 
       b = !b; 
       newList.Add(b); 
       //if(i%4096==0) { 
        //TextBox_Output.Text += "List now contains " + i + "\r"; 
       //} 
      } 

      TextBox_Output.Text += "Successfully added all the bits.\r"; 
     } 

     private void Button_TestDictionary_Click(object sender, EventArgs e) 
     { 

     } 
    } 
} 

也许你可以发现错误?

+1

.NET中的Bool存储为字节......尽管它们只能表示两种状态。所以我认为你的假设,他们“只吸〜1位”是假的:(。False == 0. True ==!False。 –

+0

这看起来对我来说是一个糟糕的设计。什么样的程序需要8GB在一个清单?不同的用例需要不同的实施策略。 –

+0

一个演化程序。为了计算最快,巨型网状树需要数万亿个元素(如果不是更多),以便计算最快。 – user978122

也许你可以发现错误?

认为的错误是在这里:

我估计他们会吸取各只有约1位,所以我会得到一些很好的度量/精密测试我的程序。

布尔需要一个字节,而不是一个位 - 所以你已经大大低估了你的列表大小。你实际上遇到了512MB的布尔错误。由于Reed Copsey的编辑速度比我快 - 我猜这个列表试图通过分配一个数组2x的大小来增加它的大小[即一个1GB的阵列],这是运行到一些.NET的限制。

这可能是开始实施分离逻辑的好时机。

+0

确实。我想我需要按照你的建议来实现一个分离器,所以它将列表大小限制为1GB或者其他任何东西。 – user978122

+0

我已经实现了一个Marshal.SizeOf()检查,但我觉得解决方案是不完整的。 – user978122

.NET中数组的大小有限制。即使您在64位平台上运行,并且设置了gcAllowVeryLargeObjects(在.NET 4.5中),但在阵列的一个维度中,您仍然限制为最多2,146,435,071个项目。

(在预4.5,你是2GB为单个对象的限制,不管多少个条目包含的内容。)

话虽这么说,一个bool由一个byte,而不是一个比特表示,所以这会比你期望的大得多。也就是说,当这个失败时,你的列表中仍然只有536,870,912个,所以理论上,在64位系统上有足够的内存,增加列表的下一个分配应该仍然在限制之内。但是,这需要程序成功地为所请求的数据分配足够大的单个连续块(其大小将是最后一块的两倍)。

+0

嗯。从我所知道的情况来看,它转换为纯粹的64位代码(whoops),并开始使用longs,我们的长度达到了134,217,728(1 GB)。仍然有点短暂......也许.Net试图分配一个更大的2 GB阵列来将1 GB阵列复制到调整大小时,这会导致内存错误? – user978122

+0

@ user978122是的。 'List '将通过每次增加一倍来重新分配。当你有一个1GB的列表,并且它增加一倍时,你会失败(甚至在64位上,除非你像在文章中提到的那样配置它) –