web-dev-qa-db-ja.com

List <string>でOutOfMemoryExceptionが発生しました-これは制限ですか、それとも何かが足りませんか?

書き直す機会があれば、私はそうしますが、とにかく、現状のコードは次のとおりです。

List<string> foobar;

次に、foobarに一連の文字列を追加します。

Count = 16777216で、メモリ不足の制限に達しました。

私の理解では、各文字列は異なるサイズになります。実際、(私のデータではなく)データを見ると、ほとんどが2文字または3文字です。

c#のリストへのデータの最大制限はいくつですか? は、最大制限が次のとおりであることを示します。

Listの現在の実装に格納できる要素の最大数は、理論的にはInt32.MaxValueであり、20億をわずかに超えています。

しかしながら:

CLRの現在のMicrosoft実装では、2GBの最大オブジェクトサイズ制限があります。 (Monoなどの他の実装にはこの制限がない可能性があります。)

私の例では、1600万件の結果*数バイトがありますか?タスクマネージャーは、使用されているギグについて表示しますが、8ギガのRAMがあります。

16777216(2 ^ 24)はかなり具体的な値のようです-疑わしいことに制限のようですが、a)これをバックアップするかb)それを回避する方法を見つけるためのドキュメントがどこにも見つかりませんか?

どんな助けでもいただければ幸いです。


いくつかのコード:

List<string> returnList = new List<string>();
SqlDataReader dr; //  executes a read on a database, have removed that part as that bit works fine

  if (dr.HasRows)
  {
      while (dr.Read())
      {
          returnList.Add(dr.GetString(0).Trim());
      }
  }

これは簡略化された形式です。OOM例外のtry/catchがいくつかありますが、これは私に悲しみを与えている実際のコードです。

14
Mark Mayo

64ビット環境で非常に大きなリストを使用しようとしている場合は、アプリケーション構成で大きなオブジェクトを有効にする必要があります。

http://msdn.Microsoft.com/en-us/library/hh285054.aspx

OOMは、Lists/ArrayListsがメモリを割り当てる方法が原因である可能性があります。これは、境界に達するたびに、サイズが2倍になろうとするためです。リストは2 ^ 24から2倍にすることはできません。サイズを事前に指定することで、理論的にはリストサイズを最大化できます。 (つまり2GB)

8
Steve Py

私が正確に行ったことをここに投稿しました。試してみる価値があります。繰り返しますが、手順は次のとおりです。

  1. ストアドプロシージャを使用して、データの各反復クエリ部分で
  2. それらを転送します
  3. 次の部分に移動します

    List<string> returnList;
    int index = 0;
    SqlCommand cmd = new SqlCommand("ExampleStoredProc", conn);
    cmd.CommandType = CommandType.StoredProcedure;
    while (true)
    {
        cmd.Parameters.Add(
            new SqlParameter("@index", index));
        SqlDataReader dr = cmd.ExecuteReader();
        if (dr.HasRows)
        {
            returnList = new List<string>();
            returnList.Add(dr.GetString(0).Trim());
            //transfer data here
        }
        else
        {
            break;
        }
        index++;
    }
    

ストアドプロシージャは次のようになります。

CREATE PROCEDURE ExampleStoredProc
    @index INT
AS
BEGIN
    SELECT * 
    FROM  veryBigTable
    WHERE Id >= (@index *1000) AND Id < ((@index + 1) * 1000)
END
GO

レコードがいくつあっても、データが多ければ多いほど、完了するまでに時間がかかります。

1
CjCoax

正しいリストサイズを手動で設定したときに2 ^ 24未満になる場合は、おそらく正しい方向に進んでいます。 1,600万に達してからリストのサイズを2倍にしようとする代わりに、最初はリストが非常に大きくなり、メモリが不足します。

これが、ラウンド数を取得している理由を説明しています。2^ 24に達した後、サイズを大きくしようとしたため、メモリの使用量が多すぎました。

リストの実装にあるものとは対照的に、それはある種の「自然な」オブジェクトサイズ制限のように私には聞こえます。

1
Jeff