20

32 ビットの .NET プロセスで 1,000 MB を超えるメモリを割り当てられないのはなぜでしょうか。次のミニ アプリケーションは、1,000 MB を割り当てた後に OutOfMemoryException をスローします。なぜ 1.8 GB ではなく 1,000 MB なのですか? 変更できるプロセス全体の設定はありますか?

static void Main(string[] args)
{
    ArrayList list = new ArrayList();
    int i = 0;
    while (true)
    {
        list.Add(new byte[1024 * 1024 * 10]); // 10 MB
        i += 10;
        Console.WriteLine(i);
    }
}

PS: ガベージ コレクションは役に立ちません。

編集して、私が望むものを明確にします。データベース/ディスクに書き込む前に非常に大量のデータを処理するサーバーアプリケーションを作成しました。すべての一時ファイルを作成する代わりに、メモリ内キャッシュを作成しました。これにより、全体が超高速になります。しかし、メモリには限りがあるので、その限界を調べてみました。そして、なぜ私の小さなテスト プログラムが正確に 1,000 MB の後に OutOfMemoryException をスローしたのか疑問に思いました。

4

7 に答える 7

18

巨大なメモリブロックを持つことは、64ビットであっても決して良い考えではありません。連続したメモリと断片化で大きな問題が発生します。

ここでの問題は、隣接するブロックを見つけることです。3GBモードを有効にしてみることができます(これはさらに数バイトを見つけるのに役立つかもしれません)が、私はそれに対して本当にアドバイスします。ここでの答えは次のとおりです。

  • 使用するメモリが少ない
  • データベース/ファイルシステムを使用する
  • x64を使用する

Eric Lippertのブログも読むことをお勧めします(彼は、.NETに関する一般的な質問ごとにブログエントリを持っているようです...)

于 2009-07-10T13:41:48.010 に答える
7

Win32 プロセスの仮想アドレス空間の制限は 1.5GB です (完全に正しいというわけではありません)。さらに、.NET フレームワークでは、.NET プロセスが消費できるメモリの割合に制限があります。machine.config には、プロセスが消費できる使用可能なメモリの % である属性 memoryLimit を持つ processModel 要素があります。デフォルト値は 60% です。

実行しているマシンに 2GB のメモリがあるか、BOOT.INI で /3GB スイッチを有効にしていない場合、プロセスごとに最大 1.3GB のメモリが得られます。

KB 記事が見つかりませんが、私の記憶が正しければ、設定に関係なく、.NET 1.x は 1.5GB (1.8GB?) の制限を超えてアドレス指定できません。

http://blogs.msdn.com/tmarq/archive/2007/06/25/some-history-on-the-asp-net-cache-memory-limits.aspx http://social.msdn.microsoft.com /Forums/en-US/clr/thread/c50ea343-b41b-467d-a457-c5a735e4dfff http://www.guidanceshare.com/wiki/ASP.NET_1.1_Performance_Guidelines_-_Caching#Configure_the_Memory_Limit

于 2009-07-10T14:14:27.517 に答える
4

私は最近、32 ビット プロセスで .NET のメモリ制限に関する広範なプロファイリングを行っています。私たちは皆、.NET アプリケーションに最大 2.4GB (2^31) を割り当てることができるという考えに悩まされていますが、残念ながらこれは真実ではありません :(。しかし、.NET 自体には独自のオーバーヘッドがあり、メモリ制限を押し上げる典型的な実世界のアプリケーションでは約 600 ~ 800MB を占めているようです. これは、整数の配列を割り当てるとすぐに、約1.4GB の場合、OutOfMemoryException() が発生することが予想されます。

明らかに 64 ビットでは、この制限はずっと後に発生します (5 年後に話しましょう :)) が、メモリ内のすべての一般的なサイズも増加します (私はそれが ~1.7 から ~2 倍であることを発見しました)。

私が確かに知っていることは、オペレーティング システムからの仮想メモリのアイデアが、1 つのプロセス内で事実上無限の割り当てスペースを提供するわけではないということです。一度に実行されるすべての (多数の) アプリケーションが 2.4GB のすべてをアドレス指定できるようにするためだけに存在します。

この洞察が少しでも役立つことを願っています。

私はもともとここに関連する何かに答えました(私はまだ初心者なので、これらのリンクをどのように行うべきかわかりません):

単一の .NET プロセスにメモリ制限はありますか

于 2009-12-15T22:47:03.877 に答える
0

アプリケーションを 64 ビット アーキテクチャにビルドすることで、最大 2 GB よりもはるかに多くのメモリを割り当てることができます。これには、Visual Studio で新しいビルド構成を作成する必要があり、アプリケーションのビルドは 64 ビット バージョンの Windows でのみ実行されます。 . .NET では、アプリケーションにデフォルトの「Any CPU」ビルド オプションを使用すると、(64 ビット Windows マシンでも) ヒープから約 1.5 GB のメモリしか割り当てることができないことがわかりました。 「Any CPU」モードで構築されている場合は、32 ビット モードでのみ実行されます。しかし、x64 アーキテクチャにコンパイルすることで、アプリケーションの実行中にヒープからはるかに多くのメモリを割り当てることができます。アプリケーションの x64 ビルドを作成する方法を以下で説明します。

繰り返しになりますが、.NET プロジェクトで通常の (既定の) "Any CPU" ビルド オプションを使用すると、アプリケーションは常に 32 ビット モードで実行され、64 ビット Windows OS でも実行されます。したがって、アプリケーションの実行中に約 1.5 ~ 2 GB を超える RAM メモリを割り当てることはできません。.NET アプリケーションを真の 64 ビット モードで実行するには、ビルド構成マネージャーにアクセスして x64 アーキテクチャ用のビルド タイプを作成し、そのビルド タイプを使用して明示的に x64 用にプログラムを再コンパイルする必要があります。x64 ビルド モード オプションは、次の手順を使用して .NET ソリューション用に作成できます。

  1. Visual Studio の [ソリューション エクスプローラー] ペインで、ソリューション アイコンを右クリックし、ポップアップ メニューから [構成マネージャー] オプションを選択します。これにより、.NET ソリューション ファイルのビルド [構成マネージャー] ダイアログ ウィンドウが開きます。
  2. ビルドの [Configuration Manager] ダイアログの右側の上部で、下矢印をクリックし、[<new>] オプションを選択します。これにより、[新しいソリューション プラットフォーム] ダイアログが開きます。
  3. [新しいソリューション プラットフォーム] ダイアログの [プラットフォーム] オプションで、ドロップダウン メニューから [x64] を選択します。次に [OK] ボタンをクリックすると、新しい x64 ビルド オプションが [構成マネージャー] ダイアログで使用できるようになります。
  4. 次に、[構成マネージャー] ダイアログで、[アクティブ ソリューション プラットフォーム] ドロップダウン メニューから [x64] を選択します。「閉じる」ボタンをクリックします。
  5. Visual Studio の [ソリューション エクスプローラー] ペインで、CS プロジェクト アイコンを右クリックし、ポップアップ メニューから [プロパティ] オプションを選択します (このメニューの一番下にある最後のオプション)。これにより、CS プロジェクトのプロパティ ウィンドウが開きます。
  6. CS プロジェクト プロパティ ウィンドウの左側で、[ビルド] タブをクリックして、コード プロジェクトのビルド プロパティを表示します。このウィンドウの上部で、「プラットフォーム」が「x64」になっていることに注意してください (デフォルトの「任意の CPU」オプションとは対照的に)。「プラットフォーム」ドロップダウンに「x64」が表示されない場合は、ここで選択する必要があります。
  7. 次に、コードをビルドするだけで、「bin」フォルダーに、アプリケーションの新しい 64 ビット ビルドを含む x64 フォルダーが作成されます。

アプリケーションの 64 ビット ビルドを 64 ビット Windows OS で使用すると、プログラムは最大 2GB をはるかに超えるメモリを割り当てることができます。おそらく最大 2^64 アドレス空間です (RAM とディスク領域が利用可能である場合、は、この回答を書いている時点での実際の制限要因です)。

アプリケーションでまだメモリが不足している場合は、Windows メモリ ページ ファイルのサイズを増やすこともできます。Windows では、ページ ファイルを使用すると、RAM メモリ領域が不足した場合に、オペレーティング システムがメモリを RAM からディスクに移動できます。ただし、RAM メモリのセクションをディスクとの間で移動するには大きな時間がかかるため、アプリケーションのパフォーマンスに大きな影響を与える可能性があります。パフォーマンスに関係なく、ページ サイズを大きくすることで、(理論的には) Windows マシンの C: ドライブに利用可能な空き領域と同じ大きさのページ ファイルを作成できます。その場合、アプリケーションは、プログラムの実行中に、たとえば最大 4 TB のメモリ (またはページ ファイル サイズが設定されているメモリの量) を割り当てることができます。Windows マシンのページ ファイル設定を変更するには、

  1. [この PC] を右クリックし、ポップアップ メニューの [プロパティ] オプションを選択して、[システムのプロパティ] ダイアログを開きます。これは、Windows の新しいバージョン (Windows 10、Win 2012 Server など) でも、[スタート] > [コントロール パネル] > [システムとセキュリティ] > [システム] に移動して実行できます。
  2. [システム] ダイアログの左側で、[システムの詳細プロパティ] オプションをクリックします。これにより、Windows の従来の [システム プロパティ] ダイアログの [詳細] タブが表示されます。
  3. [システムのプロパティ] ダイアログの [詳細設定] タブで、[パフォーマンス] ボックスの [設定] ボタンをクリックします。これにより、[パフォーマンス オプション] ダイアログが開きます。
  4. [パフォーマンス オプション] ダイアログで、[詳細設定] タブをクリックして、Windows メモリ ページ ファイルの現在のサイズ設定を確認します。
  5. ページ ファイルのサイズを大きくするには、[変更] ボタンをクリックすると、[仮想メモリ] ダイアログが開きます。
  6. [仮想メモリ] ダイアログで [C:] ドライブを選択し、[カスタム サイズ] で [初期] と [最大] のサイズを設定します。C: ドライブの最大空き容量まで任意のサイズを使用できますが、この変更を行うと、ハード ドライブ上のページ ファイル用にその容量が確保されます。
  7. 次に、すべてのダイアログで [OK] をクリックして、新しい設定をコミットします。次に、コンピュータを再起動して、すべての変更が適切に完了し、新しいページ ファイル設定が動作していることを確認します。

とにかく、64 ビットの Windows マシンで実行している場合でも、.NET アプリケーションでこの 1.5 ~ 2 GB のメモリ制限の問題が発生する理由を人々が理解するのに役立つことを願っています。これは人々にとって非常に紛らわしい問題になる可能性があり、私の説明が理にかなっていることを願っています. 必要に応じて、この回答に関する質問を私にメッセージを送ってください。

于 2017-12-12T08:10:11.767 に答える
-1

ここでの問題は、このアプリケーションが作成するループごとに 10MB を追加することであり、ループは "while(true)" であり、アプリケーションが停止するまでこれらの 10MB を追加することを意味すると思います。したがって、100 ループ実行すると、RAM に 1GB 近く追加されたことになります。これは 30 秒以内に実行されたと思います。私のポイントは、ループごとに10メガバイトのメモリを、決して終わらないループでしようとしているということです

于 2014-12-17T14:38:33.550 に答える
-2

私があなたの要点を理解していない場合は本当に申し訳ありませんが、:

static void Main(string[] args)
{
    ArrayList list = new ArrayList();
    int i = 0;
    while (true)
    {
        using(byte newBt = new byte[1024 * 1024 * 10])
        {
            list.Add(newBt); // 10 MB
            i += 10;
            Console.WriteLine(i);
        }
    }
}

使用方法は試しましたか?これはばかげた質問かもしれませんが、なぜ永遠のループを作成したのですか? O コードを試してみると、シンボル >.> xD が取り除かれます。

ソース: http://msdn.microsoft.com/en-us/library/yh598w02(v=vs.80).aspx

于 2012-04-20T19:15:15.147 に答える