web-dev-qa-db-ja.com

Java 32ビットXmxとJava 64ビットXmx

私はこれと本当に混乱しています。

Java docsによると、Xmxは最大許容ヒープサイズです。
Xmsは最低限必要なJavaヒープサイズであり、JVMの起動時に割り当てられます。

32ビットJVM(4GB ram)では、Java -Xmx1536M HelloWorldが十分なメモリエラーを割り当てられません。
64ビットJVM(4GB Ram)では、Java -Xmx20G HelloWorldは問題なく動作しますが、仮想メモリまたは物理メモリがそれほど割り当てられていません。

このことから、Java 32ビットはJVM起動時に1536Mを割り当てていますが、Java 64ビットはそうではありません。

なぜ?単純なHello Worldの実行には1536Mは必要ありません。私は1536Mが最大であることを指定しているだけであり、それが必要であるということではありません。

説明は誰か?

14
user3219957

メモリの割り当てとアドレス空間の割り当てには違いがあります。 Oracle JVMは、起動時にアドレス空間を割り当てて、ヒープが連続していることを確認しています。これにより、特定の最適化をヒープで使用できます。

割り当てが失敗した場合、Javaは起動しません...ご覧のように。必ずしも多くのメモリを使用しているわけではありませんが、必要なアドレス空間を事前に割り当てています。 -Xmx1536m、それは大丈夫だと言っています。必要な場合に備えて割り当てる必要があります...連続している必要があるため、前もって行うため、保証することができます(または試行に失敗します)。

この動作は、32ビットと64ビットの両方のJVMで同じです。表示されているのは、32ビットプロセスの2 GBのプロセスごとのアドレススペースの制限です(少なくともWindowsではこれが制限です。他のプラットフォームでは少し大きい可能性があります)。この割り当ては32ビットで失敗します。 -bitはアドレス空間がはるかに大きいため、問題はありません。しかし、あなたは言う、1536mは2GB未満です、私は良いはずですよね?不正解です。アドレススペースに割り当てられているのはヒープだけではありません。DLLやその他のものもアドレススペースに割り当てられています。したがって、32ビットで最大2GBの連続する1536mチャンクを取得することは、残念ながら非常にまれです。特に不適切な断片化を伴う32ビットプロセスで1000m未満の値が失敗することを確認しました。通常、32ビットで指定できる最大ヒープは1200-1300mです。

最近のOSでは、 [〜#〜] aslr [〜#〜] (アドレス空間レイアウトのランダム化)により、32ビットプロセスのアドレス空間の断片化が悪化します。セキュリティ上の理由から、DLLをランダムなアドレスに意図的にロードします。32ビットで大きな連続ヒープを取得できる可能性がさらに低くなります。

64ビットでは、アドレス空間が非常に大きいため、断片化は問題ではなくなり、巨大なヒープを問題なく割り当てることができます。 4GBのRAMですが、プロセスあたり2GBのアドレス空間の制限(少なくともWindowsでは))は、通常、最大ヒープが通常1300m程度であることを意味します。

21
Joshua McKinnon

実際、アプリケーションは起動時にXmxメモリを割り当てていません。

-Xmsパラメータは、起動メモリを構成します。 ( JVMを起動するときのXmsおよびXmxパラメータは何ですか?

64ビット環境では、32ビットよりも大きなメモリ割り当てが可能です。しかし、実際には、メモリRAMではなく、HDスペースを使用しています。

詳細については、この他の投稿を参照してください。

64ビットJavaでの最大安全JVMヒープサイズの推定

7
edubriguenti

Windowsでは、VirtualAllocなどのネイティブWinAPI低レベル関数とのメモリ割り当て操作に違いがあります。

「予約」とは、仮想メモリのこの領域を実際に使用可能にすることなく、プロセスのアドレス空間内に連続した領域を割り当てることを意味します。割り当てられた領域は、実際の物理RAMまたはスワップスペースに支えられておらず、空きメモリを消費しません。アプリケーションは、プロセッサのメモリアドレス指定機能(ビット数)によってのみ制限されるアドレススペースを予約できます。

「コミット」とは、以前に「予約」されたメモリの一部を実メモリでバッキングすることを意味します-RAMまたはスワップ領域。これにより、プロセスによって実際に読み取り/書き込み可能になります。このメモリは、利用可能なOS仮想メモリプールから取得されます(RAMとスワップ)。

メモリを "コミット"(プールから空白ページを取得)する代わりに、以前に "予約"されたメモリにファイルを "マッピング"します。これはスワッププールからメモリを消費しませんが、プロセスのアドレス空間のその特定の領域のための専用スワップ空間と同様の方法でマップされたファイルを使用します。

ネイティブWindowsアプリケーション(JVM自体など)は、将来必要になるすべてのヒープ用にメモリを予約しますが、必要な場合にのみコミットします。 malloc()スタイルの関数や「新しい」演算子などの高レベルのメモリ操作は、必要に応じて実際に「コミット」を実行するか、CPU集中型カーネルであるため、メモリを大きなチャンクによって先にコミットして、独自のヒープ管理ロジックユーザーモードを実行します。呼び出し、ページ(4k)の粒度で動作します。

プロセスの起動中、JVMは-Xmxメモリを「予約」しますが、「コミット」するのはその-Xms量のみです。残りの予約済みメモリは、ヒープの増加に応じてオンデマンドでコミットされます。したがって、ヒープは使用可能なメモリまたは-Xmxパラメータのいずれか小さい方まで大きくなる可能性があります。