2

解決済み:新しいプロジェクトを作成するとき、Visual Studio 2012 は既定で 64 ビット アプリをビルドすると誤って想定していました。[ソリューション プロパティ] の [ビルド] タブに、[32 ビットを優先] というチェック ボックスがあります。このチェックボックスをオフにしてソリューションを再構築したところ、一度に 200 を超えるビットマップを読み込んで処理することができました。解決策を丁寧に指摘してくれた Mike Trusov に感謝します。

元の質問:小さな問題が発生しました。8 GB システムの RAM にロードしたい 150 を超えるグレースケール ビットマップがありますが、例外をスローせずに 50 程度を超えることはできないようです。ビットマップを配列にロードしようとしましたが、.NET には 2GB の制限があるため、もちろんこれは失敗の原因です。しかし、2GB 相当のビットマップがロードされるずっと前に失敗しました。それで、それらを にロードしようとしましたList<List<Bitmap>>が、それでもほぼ同じ場所で失敗します。例外が発生した時点で、タスク マネージャーは、3939 MB の利用可能な RAM がいっぱいになるのを待っていると言います。非常に奇妙な。

これらのビットマップが RAM で連続している必要はありません。それらは、私が気にかけているすべての 16 MB の割り当ての散らばった束になる可能性があります。利用可能な RAM をたくさんのビットマップで埋めたいだけです。それで全部です。

プログラムを開始したときに使用可能な RAM の量に応じて、例外はさまざまな時点で OutOfMemory 例外または ArgumentException でした。どちらの場合も、スタック トレースは内部で停止しますSystem.Drawing.Bitmap..ctor(String filename)。例外の発生時に特定のファイルがロードされていることに問題はありません。実際、別の(または重複する)ビットマップのセットをロードすると、同じ反復でエラーが発生します。

これを行う方法について私に貸してくれる手がかりを持っている人はいますか? 奇妙な方法で .NET の 2GB 制限に達していますか?

いくつかの質問とコメントへの回答: 8 GB の RAM を搭載したコンピューターで Visual Studio 2012、.NET 4.5、64 ビット Windows 7 を使用しています。はい、さまざまな理由 (パフォーマンス、画像処理の理由など) から、これらすべてのビットマップを同時に RAM に保存する必要があります。gcAllowVeryLargeObjects の使用について熟考しましたが、すべてのビットマップを連続したメモリの長いチャンクに格納する必要はありません。各ビットマップが独自の個別のメモリ割り当てを使用することをお勧めします。さらに、64 GB の RAM を搭載したマシンを使用している場合、そのサイズのビットマップを 150 個に制限するのはばかげています。これらのビットマップが OutOfMemoryException をスローせずに読み込まれないのはなぜですか?

私には、.NET がすべてのビットマップを単一の 2 GB リージョンに保持しようとしているように見えます。各ビットマップに (ここで知っている以上のことを言うと) 独自の個別のアドレス空間を持たせる方法があれば、問題が解決する可能性があります。MS-DOS の昔の言語を呼び出すには、ロング ポインターを使用して far メモリを割り当ててアクセスし、すべてのデータを単一の near セグメントにスタックさせないようにします。

配列コードは次のとおりです。

    List<String> imageFiles;            // List of .bmp filenames.
    Bitmap[] bmps = new Bitmap[100];    // Stores/accesses the Bitmaps.

    private void goButton_Click(object sender, EventArgs e)
    {
        int i;

        // Load the bitmaps
        if (bmps[0] == null)
        {
            // Load the list of bitmap files.
            imageFiles = Directory.EnumerateFiles(@"C:\Temp", "*.bmp", SearchOption.TopDirectoryOnly).ToList();

            // Read bitmap files
            for (i = 0; i < bmps.Length; ++i)
            {
                bmps[i] = new Bitmap(imageFiles[i]);    // <-- Exception occurs here when i == 52 or so.
            }
        }
    }

List> コードは次のとおりです。

    List<String> imageFiles;                                // List of .bmp filenames.
    List<List<Bitmap>> bmps = new List<List<Bitmap>>(100);  // Stores/accesses the Bitmaps.

    private void goButton_Click(object sender, EventArgs e)
    {
        int i;

        // Load the bitmaps
        if (bmps.Count == 0)
        {
            // Load the list of bitmap files.
            imageFiles = Directory.EnumerateFiles(@"C:\Temp", "*.bmp", SearchOption.TopDirectoryOnly).ToList();

            // Read bitmap files
            for (i = 0; i < 100; ++i)
            {
                // Load the bitmap into temporary Bitmap b.
                Bitmap b = new Bitmap(imageFiles[i]);   // <-- Exception occurs here when i == 52 or so.

                // Create and add a List<Bitmap> that will receive the clone of Bitmap b.
                bmps.Add(new List<Bitmap>(1));

                // Clone Bitmap b and add that cloned Bitmap to the Bitmap of List<Bitmap>.
                bmps[i].Add((Bitmap)b.Clone());

                // Dispose Bitmap b.
                b.Dispose();
            }
        }
    }
4

2 に答える 2

1

64ビットOSで実行されている64ビットアプリ(プロジェクト設定を確認してください-x86ベースの任意のCPU用に新しい構成を作成する必要がある場合があります)で2GBを超えるビットマップをメモリにロードしても問題はありません(私はあなたがそうであると推測しています)。また、単純なリストも機能するはずです。

    var imageFiles = Directory.EnumerateFiles(@"C:\Temp", "*.bmp", SearchOption.TopDirectoryOnly).ToList();
    var lst = new List<Bitmap>();
    foreach (var imageFile in imageFiles)
    {
        lst.Add(new Bitmap(imageFile));
    }
于 2013-03-18T02:37:16.990 に答える
0

それらはすべて同時にロードする必要がありますか? たとえば 20 個をロードすると、それらを処理または表示している間に、バックグラウンド スレッドで次の 20 個を準備できます。

于 2013-03-18T02:35:44.150 に答える