2

そのため、追加専用の 64 ビットっぽいリストとディクショナリを開発していますが、メモリ エラーが発生しました。私はある時点でそうするだろうと考えていましたが、64 MB ではそうではありませんでした。これはやや予想外の結果であり、64 MB で問題が発生する理由を説明してくれる人がいることに興味があります。

新しい List クラスのテストは、単純に 8 GB 相当の bool を作成して List にロードする試みです。私は、それらがそれぞれ最大 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)
        {

        }
    }
}

おそらく、エラーを見つけることができますか?

4

2 に答える 2

6

おそらく、エラーを見つけることができますか?

エラーはここにあると思います:

私は、それらがそれぞれ最大 1 ビットしか消費しないと考えたので、プログラムをテストするためのいくつかの優れた指標/精度が得られるでしょう。

bool は 1 ビットではなく 1 バイトを取るため、リストのサイズを大幅に過小評価しています。実際には、512MB のブール値でエラーが発生しています。Reed Copsey は私より少し速く編集しているので、現在のサイズの 2 倍の配列 [つまり 1GB 配列] を割り当ててリストのサイズを大きくしようとしていると思われます。

これはおそらく、分割ロジックの実装を開始するのに適した時期です。

于 2012-10-10T01:38:49.483 に答える
4

.NET の配列のサイズには制限があります。64 ビット プラットフォームで実行していて、 (.NET 4.5 で) gcAllowVeryLargeObjectsを設定した場合でも、配列の 1 つの次元で最大 2,146,435,071 項目に制限されます。

(4.5 より前では、含まれるエントリの数に関係なく、1 つのオブジェクトに対して 2 GB に制限されていました。)

そうは言っても、 aboolは 1 ビットではなく 1 で表されるbyteため、これは予想よりもかなり大きくなります。そうは言っても、これが失敗した場合でもリストには 536,870,912 しかないため、理論的には、十分なメモリを備えた 64 ビット システムでは、リストを拡張するための次の割り当ては依然として制限内にあるはずです。ただし、これには、プログラムが、要求されたデータに十分な大きさの単一の連続したメモリ チャンクを正常に割り当てる必要があります (最後のチャンクのサイズの 2 倍になります)。

于 2012-10-10T01:38:05.007 に答える