プロが教える店舗&オフィスのセキュリティ対策術

言語はC#、開発環境はVisualStudio2008、OSはwindows7です。
また、メモリは4GBです。

HashSetに次々に整数を格納していくテストコードを作成したのですが、
メモリにはまだ余裕があるにも関わらず、
5000万個程度の整数を格納するとexeが落ちます。

これはどういう事情なのかを教えてください。
例えば、exeファイルにサイズ制限があるのか、
HashSetに上限があるのか、
HashSetは連続したメモリ領域を確保しないといけない、とか
そのような事情があるのでしょうか?

A 回答 (2件)

何か例外がスローされてると思いますが、それは確認されましたか?


VisualStudio 2013でですが私の方で試してみましたけど

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

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
HashSet<int> a = new HashSet<int>();
for (int i = 0; i < 50000000; i++)
{
try
{
a.Add(i);
}
catch (Exception e)
{
Console.WriteLine("i={0}", i);
Console.WriteLine("{0}", e);
break;
}
}
}
}
}

を32ビットモードで実行すると

i=23997907
System.OutOfMemoryException: 種類 'System.OutOfMemoryException' の例外がスローされました。
場所 System.Collections.Generic.HashSet`1.SetCapacity(Int32 newSize, Boolean forceNewHashCodes)
場所 System.Collections.Generic.HashSet`1.IncreaseCapacity()
場所 System.Collections.Generic.HashSet`1.AddIfNotPresent(T value)
場所 System.Collections.Generic.HashSet`1.Add(T item)
場所 ConsoleApplication1.Program.Main(String[] args) 場所 c:\~\Program.cs:行 18

で例外がスローされているのが確認できました(例外の意味までは説明しません)。
64ビットモードで実行する分には正常に終わります。

>メモリにはまだ余裕があるにも関わらず、

これはどこで確認されましたか?
Windowsのタスクマネージャーなどでしたら空きがあるように思えても32ビットアプリケーションは通常2GBまでしか使用できません。
また#1の方も説明されていますがHashSetが要素を管理する分のメモリもありますし、C#ではintもSystem.Int32構造体の別名なので4バイトというわけではなく、単純に「メモリ使用量4*5000万バイト」という計算にはならないので注意してください。
    • good
    • 0
この回答へのお礼

ありがとうございます。
64ビットwindows8、64ビットモードでコンパイルしたところ、
実行できるようになりました。

お礼日時:2014/01/27 22:07

C#は使った事はないので類推ですが、やはりOS或いはC#プログラムのサイズリミットに掛かっているのではないかと思われます。



先ずプログラムリンク時に(デフォルトで?)指定されるプログラムサイズリミット値、或は実行時のサイズ制限値等を確認下さい。

HashSetではObject対応でhash value:hvが計算され、例えばHash_Table_Base+hv*4でindex引きして同一hvを持ったObjectのchainを辿って指定されたObjectがないかスキャンしたりします。

このHash_Tableは連続番地に割り当てる必要があります。
integer object一個毎にinteger valueとして4byte, object headerに4-8byte, 同一hash value chainに4byte,
Hash_Tableのentry数の割合は全object数の例えば1/4 - 1 (1.25)倍程度, 1enty当りpointer一個4byte程度は必要でしょう。

従って 1 Integer Object当り12-16byte, 連続割り当てのHash_Table Areaとして Object数*(1-4)バイト程度は必要となります。
なお、Hash_Table Areaはentry数が多くなるのに従って、最初は100entry, 1000, 10000entry等と再構成されて行きます。

50M entry * 20 = 1GB程度、その内200MBは連続番地等が必要となる可能性があると思われます。
タスクマネージャでテストプログラムのメモリ使用量とentry数との関係を確認する等して下さい。
    • good
    • 0
この回答へのお礼

ありがとうございます。
64ビットモードでコンパイルしたところ、
実行できるようになりました。

お礼日時:2014/01/27 22:06

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!