6

20000を超えるアイテムが連続しているC#WinFormsで正方行列を宣言する必要があります。32ビットで約2GBの.Netオブジェクトのサイズ制限を読み、64ビットOSでも同じケースを読みました。だから私が理解したように、単一の答えは、安全でないコードまたはC++コンパイラで構築された別のライブラリを使用することです。

ushort [20000,20000]は2GBよりも小さいので、私にとっての問題は価値がありますが、実際には700MBのメモリを割り当てることさえできません。私の制限は650MBですが、その理由がわかりません。32ビットのWinXPと3GBのメモリがあります。Marshal.AllocHGlobal(700 << 20)を使用しようとしましたが、OutOfMemoryExceptionがスローされ、メモリを割り当てようとする前にGC.GetTotalMemoryが4.5MBを返します。

多くの人が安全でないコードを使用すると言っているだけですが、ヒープ内で2次元配列を宣言する方法(どのスタックもそれほど大量のデータを保持できない)とポインターを使用してそれを操作する方法の例を見つけることができません。安全でない{}ブラケット内の純粋なC++コードですか?

PS。なぜこんなに巨大な配列が必要なのかと聞かないでください...しかし、必要に応じて、テキスト(本など)を分析し、多くのインデックスを見つける必要があります。だから答えは-単語間の関係の行列

編集:誰かが安全でないコードでポインタを使用して行列を操作する小さな例を提供していただけませんか。32ビット未満ではより多くのスペースを割り当てることは不可能であることを私は知っていますが、私はそのような例をグーグルで検索することに多くの時間を費やし、何も見つかりませんでした

4

6 に答える 6

5

なぜ巨大な2Dアレイを要求するのですか?たとえば、ジャグ配列を使用してこれをシミュレートできます---ほぼushort[][]同じ速度で、同じ単一オブジェクトの制限に達することはありません。もちろん、まだbuckets-o-RAMが必要なので、x64が暗示されます...

        ushort[][] arr = new ushort[size][];
        for(int i = 0 ; i < size ; i++) {
            arr[i] = new ushort[size];
        }

それに加えて、スパース配列、eta-vector、およびそのすべてのジャズを見たいと思うかもしれません。

于 2010-04-07T15:38:44.970 に答える
4

32ビットWindowsで2Gbの割り当てにさえ近づくことができない理由は、CLRのアレイが連続したメモリに配置されているためです。32ビットWindowsでは、アドレス空間が制限されているため、プロセスの仮想アドレス空間に2Gbの穴のようなものはありません。あなたの実験は、利用可能なアドレス空間の最大の領域が650Mbであることを示唆しています。64ビットWindowsに移行すると、少なくとも2Gbの完全な割り当てを使用できるようになります。

32ビットWindowsでの仮想アドレス空間の制限は、コンピューターにある物理メモリの量(この場合は3Gb)とは関係がないことに注意してください。代わりに、CPUがメモリアドレスをアドレス指定するために使用するビット数によって制限が発生します。32ビットWindowsは、当然のことながら、32ビットを使用して各メモリアドレスにアクセスします。これにより、アドレス指定可能な合計メモリスペースは4Gバイトになります。デフォルトでは、Windowsは2Gbを保持し、現在実行中のプロセスに2Gbを提供するため、CLRが2Gb割り当てのようなものを見つけられない理由がわかります。いくつかのトリックを使用すると、Windowsが1Gbのみを保持し、実行中のプロセスに3Gbを与えるように、OS/ユーザーの割り当てを変更できます。

于 2010-04-07T15:54:30.380 に答える
2

私はとても幸せだ!:)最近、私は主題の問題を試しました-データベースを使用してそれを解決しようとしましたが、この方法は完璧にはほど遠いことがわかりました。マトリックス[20000,20000]は単一のテーブルとして実装されました。インデックスを適切に設定しても、4億を超えるレコードを作成するために必要な時間は、私のPCでは約1時間です。それは私にとって重要ではありません。次に、その行列を処理するためにアルゴリズムを実行し(同じテーブルを結合するには、2回必要です!)、30分以上動作した後、1つのステップも実行されませんでした。その後、唯一の方法は、メモリ内でのみそのようなマトリックスを操作し、C#に戻る方法を見つけることであると理解しました。

パイロットアプリケーションを作成して、メモリ割り当てプロセスをテストし、さまざまな構造を使用して割り当てプロセスが停止する場所を特定しました。

私の最初の投稿で述べたように、 32ビットWinXPでは約650MBの2次元アレイを使用して割り当てることができます。Win7と64ビットコンパイルを使用した後の結果も悲しいものでした-700MB未満。

単一の2次元配列[、]の代わりにJAGGED ARRAYS [] []を使用しました。結果は、以下のとおりです。

リリースモードで32ビットアプリとしてコンパイル-WinXP32ビット3GBphys。mem。-1.45GB を64ビットアプリとしてリリースモードでコンパイル-VMでWin764ビット2GB - 7.5GB

-テストに使用したアプリケーションのソースは、この投稿に添付されています。ソースファイルを添付する方法がここに見つからないので、設計部分を説明し、ここに手動コードを入れてください。WinFormsアプリケーションを作成します。デフォルトの名前(ボタン1つ、numericUpDown 1つ、リストボックス1つ)を使用して、このようなコントロールをフォームに配置します。.csファイルに次のコードを追加して実行します。

private void button1_Click(object sender, EventArgs e)
        {
            //Log(string.Format("Memory used before collection: {0}", GC.GetTotalMemory(false)));
            GC.Collect();
            //Log(string.Format("Memory used after collection: {0}", GC.GetTotalMemory(true)));
            listBox1.Items.Clear();
            if (string.IsNullOrEmpty(numericUpDown1.Text )) {
                Log("Enter integer value");
            }else{
                int val = (int) numericUpDown1.Value;
                Log(TryAllocate(val));
            }
        }

        /// <summary>
        /// Memory Test method
        /// </summary>
        /// <param name="rowLen">in MB</param>
        private IEnumerable<string> TryAllocate(int rowLen) {
            var r = new List<string>();
            r.Add ( string.Format("Allocating using jagged array with overall size (MB) = {0}", ((long)rowLen*rowLen*Marshal.SizeOf(typeof(int))) >> 20) );
            try {
                var ar = new int[rowLen][];
                for (int i = 0; i < ar.Length; i++) {
                    try {
                        ar[i] = new int[rowLen];
                    }
                    catch (Exception e) {
                        r.Add ( string.Format("Unable to allocate memory on step {0}. Allocated {1} MB", i
                            , ((long)rowLen*i*Marshal.SizeOf(typeof(int))) >> 20 ));
                        break;
                    }
                }
                r.Add("Memory was successfully allocated");
            }
            catch (Exception e) {
                r.Add(e.Message + e.StackTrace);
            }
            return r;
        }

        #region Logging

        private void Log(string s) {
            listBox1.Items.Add(s);
        }

        private void Log(IEnumerable<string> s)
        {
            if (s != null) {
                foreach (var ss in s) {
                    listBox1.Items.Add ( ss );
                }
            }
        }

        #endregion

問題は私のために解決されました。皆さん、よろしくお願いします!

于 2010-04-12T09:21:51.323 に答える
0

スパース配列が適用されない場合は、メモリマップトファイルに関連するプラットフォームAPIを使用してC / C ++で実行することをお勧めします:http://en.wikipedia.org/wiki/Memory-mapped_file

于 2010-04-07T15:45:30.387 に答える
0

あなたがやろうとしていることを説明したなら、それは助けるのがより簡単でしょう。たぶん、そのような大量のメモリを一度に割り当てるよりも良い方法があります。

再設計は、このすばらしいブログ投稿の第1の選択肢でもあります。

BigArray、2GBのアレイサイズ制限を回避

この記事で提案されているオプションは次のとおりです。

于 2010-04-07T15:49:36.267 に答える
0

OutOfMemoryExceptionについては、次のスレッドをお読みください(特に、nobugzとBrian Rasmussenの回答):
Microsoft Visual C#2008ロードされたdllの数を減らす

于 2010-04-07T15:54:41.373 に答える