6

私はProject Eulerの演習をいくつか行っていますが、2,147,483,647 ( C#の上限) を超える配列が必要なシナリオに遭遇しました。int

確かにこれらは大きな配列ですが、たとえば、これはできません

// fails
bool[] BigArray = new BigArray[2147483648];

// also fails, cannot convert uint to int
ArrayList BigArrayList = new ArrayList(2147483648); 

では、より大きな配列を使用できますか?

編集:アトキンのふるい用だったので、本当に大きなものが欲しかったのです:D

4

6 に答える 6

12

これほど大きな配列を扱っているときはいつでも、おそらく問題に対するより良い解決策を見つけようとするべきです。しかし、そうは言っても、私はまだあなたの質問に答えようとします.

この記事で説明したように、.Net のオブジェクトには 2 GB の制限があります。すべての x86、x64、および IA64 用。

32 ビット Windows オペレーティング システムと同様に、64 ビット Windows オペレーティング システムで 64 ビット マネージド アプリケーションを実行しているときに作成できるオブジェクトのサイズには 2 GB の制限があります。

また、スタックに大きすぎる配列を定義すると、スタック オーバーフローが発生します。ヒープ上に配列を定義すると、すべてを 1 つの大きな連続ブロックに割り当てようとします。ヒープに暗黙的な動的割り当てがある ArrayList を使用することをお勧めします。これで 2GB を超えることはできませんが、おそらくそれに近づくことができます。

x64 または IA64 アーキテクチャとオペレーティング システムを使用している場合にのみ、スタック サイズの制限が大きくなると思います。x64 または IA64 を使用すると、32 ビットではなく 64 ビットの割り当て可能なメモリが得られます。

配列リストを一度に割り当てることができない場合は、おそらく部分的に割り当てることができます。

6 GB の RAM を搭載した x64 Windows 2008 マシンで、配列リストを使用して一度に 1 つのオブジェクトを追加すると、ArrayList を取得できる最大サイズは 134217728 になります。メモリをあまり使用しません。おそらく、RAM を使用する代わりにファイルに書き込みます。

于 2009-02-21T20:33:01.487 に答える
8

配列の制限は、64ビットでもint32に固定されています。1 つのオブジェクトの最大サイズには上限があります。ただし、非常に簡単に大きなギザギザの配列を作成できます。

悪い; x64 では参照が大きくなるため、ref 型の配列の場合、実際には 1 つの配列で取得できる要素が少なくなります。

ここを参照してください:

2.0 .Net ランタイムの 64 ビット バージョンで配列の最大サイズが 2GB に制限されている理由について、多くの問い合わせを受けました。最近話題になっているように思われるので、少し背景を理解し、この制限を回避するためのオプションについて議論する必要がありました。

最初にいくつかの背景。.Net ランタイム (CLR) の 2.0 バージョンでは、ランタイムの 64 ビット バージョンでも、GC ヒープで許容される最大オブジェクト サイズを 2GB に維持するという意識的な設計上の決定を行いました。これは 32 ビット CLR の現在の 1.1 実装と同じですが、実際に 32 ビット CLR に 2GB オブジェクトを割り当てるのは難しいでしょう。なぜなら、仮想アドレス空間が断片化しすぎて現実的に 2GB を見つけることができないからです。穴。一般に、インスタンス化されたときに 2GB を超える (またはそれに近い) 型の作成には特に関心はありませんが、配列はマネージド ヒープ内で作成される特別な種類のマネージド型であるため、この制限にも悩まされます。


.NET 4.5 では、オプションでgcAllowVeryLargeObjectsフラグによってメモリ サイズの制限が削除されることに注意してください。ただし、これは最大ディメンションサイズを変更しません。重要な点は、カスタム型の配列または多次元配列がある場合、メモリ サイズが 2GB を超えることができるようになったことです。

于 2009-02-21T20:38:16.017 に答える
6

それほど大きな配列は必要ありません。

メソッドでリソースの問題が発生した場合は、リソースを拡張する方法だけでなく、メソッドも確認してください。:)

これは、エラトステネスのふるいを使用して素数を計算するために3MBのバッファーを使用するクラスです。このクラスは、素数を計算した距離を追跡し、範囲を拡張する必要がある場合は、さらに300万個の数値をテストするためのバッファーを作成します。

見つかった素数をリストに保持し、範囲が拡張されると、前の素数を使用してバッファ内の数を除外します。

私はいくつかのテストを行いましたが、約3MBのバッファーが最も効率的です。

public class Primes {

   private const int _blockSize = 3000000;

   private List<long> _primes;
   private long _next;

   public Primes() {
      _primes = new List<long>() { 2, 3, 5, 7, 11, 13, 17, 19 };
      _next = 23;
   }

   private void Expand() {
      bool[] sieve = new bool[_blockSize];
      foreach (long prime in _primes) {
         for (long i = ((_next + prime - 1L) / prime) * prime - _next;
            i < _blockSize; i += prime) {
            sieve[i] = true;
         }
      }
      for (int i = 0; i < _blockSize; i++) {
         if (!sieve[i]) {
            _primes.Add(_next);
            for (long j = i + _next; j < _blockSize; j += _next) {
               sieve[j] = true;
            }
         }
         _next++;
      }
   }

   public long this[int index] {
      get {
         if (index < 0) throw new IndexOutOfRangeException();
         while (index >= _primes.Count) {
            Expand();
         }
         return _primes[index];
      }
   }

   public bool IsPrime(long number) {
      while (_primes[_primes.Count - 1] < number) {
         Expand();
      }
      return _primes.BinarySearch(number) >= 0;
   }

}
于 2009-02-21T21:21:17.613 に答える
3

64 ビット CLR 内でも、オブジェクトあたり 2GB (またはおそらく 1GB - 正確には覚えていません) の制限があると思います。これにより、より大きな配列を作成できなくなります。Array.CreateInstance がサイズに Int32 引数しかとらないという事実も示唆的です。

より広い観点から言えば、それほど大きな配列が必要な場合は、問題へのアプローチ方法を実際に変更する必要があると思います。

于 2009-02-21T20:38:46.403 に答える
1

私は C# の初心者 (つまり、今週学習中) であるため、ArrayList の実装方法の正確な詳細はわかりません。ただし、ArrayList の例では型を定義していないため、配列はオブジェクト参照の配列として割り当てられると思います。これは、アーキテクチャによっては、実際に 4 ~ 8Gb のメモリを割り当てていることを意味する場合があります。

于 2009-02-22T00:25:07.623 に答える
0

MSDN によると、バイト配列のインデックスは 2147483591 を超えることはできません。4.5 より前の .NET では、配列のメモリ制限でもありました。.NET 4.5 では、この最大値は同じですが、他の型では最大 2146435071 になる可能性があります。

これは説明のためのコードです:

    static void Main(string[] args)
    {
        // -----------------------------------------------
        // Pre .NET 4.5 or gcAllowVeryLargeObjects unset
        const int twoGig = 2147483591; // magic number from .NET

        var type = typeof(int);          // type to use
        var size = Marshal.SizeOf(type); // type size
        var num = twoGig / size;         // max element count

        var arr20 = Array.CreateInstance(type, num);
        var arr21 = new byte[num];

        // -----------------------------------------------
        // .NET 4.5 with x64 and gcAllowVeryLargeObjects set
        var arr451 = new byte[2147483591];
        var arr452 = Array.CreateInstance(typeof(int), 2146435071);
        var arr453 = new byte[2146435071]; // another magic number

        return;
    }
于 2014-09-15T20:47:26.120 に答える