実稼働マシンで単純なJavaプログラムを実行すると、このプログラムは10Gのvirtをより多く消費することに気付きました。仮想メモリはそれほど重要ではないことは知っていますが、が必要です。
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
try {
Thread.sleep(10000);
} catch(InterruptedException e) {
/* ignored */
}
}
}
その小さなプログラムを実行したときにtop
が言っていることは次のとおりです。
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
18764 myuser 20 0 10.2g 20m 8128 S 1.7 0.1 0:00.05 Java
なぜこれが起こっているのか知っていますか?
uname -aのコメント:
Linux m4fxhpsrm1dg 2.6.32-358.18.1.el6.x86_64 #1 SMP Fri Aug 2 17:04:38 EDT 2013 x86_64 x86_64 x86_64 GNU/Linux
古い32ビットLinuxマシンでは、同じプログラムは約1Gのvirtしか消費しません。古いマシンには4GBのRAMがあり、新しいマシンには32GBがあります。
初期ヒープと最大ヒープのデフォルトサイズ は、マシンの物理メモリの割合として定義されており、現在の実稼働サーバーでは、ロット全体がになる傾向があります。
-Xmsおよび-Xmxコマンドラインオプション で両方を選択できます。
仮想メモリは本当に重要ではありません。
32ビットと64ビットの基本的な違いは、64ビットのアドレス空間が非常に大きいことです。 10 GiBが非常によく見える場合、64ビットの.NETはこのようなメモリのTiBを使用できることに注意してください。しかし、32ビットでは、.NETははるかに保守的です(など) JVM)-アドレス空間は4 GiBtotal-それは多くありません。
しかし、それは無関係です-それは重要ではありません。これはプログラミングを大幅に簡素化するものであり、ホストOSに悪影響を与えるものではありません。 VMが使用するための連続したアドレス空間を作成します。これは、ヒープ(または、さらに悪いことにスタック)を断片化する必要がないことを意味します。より多くの「実際の」メモリが必要になると、MiBのみになります。最終的に仮想メモリをコミットすると、わずかに実際になります-その時点で、多少のバックアップが必要ですsomeデータストレージ-ページ(スワップ)ファイルでも物理RAMでもかまいません。
ポイントは、メモリの物理的な場所は必ずしも連続的ではないが、それは手の届かないところで行われ、マッピングは一般的に非常に高速です。一方、たとえば、10個の異なる仮想アドレスメモリブロックに実際に断片化されている配列にインデックスを付ける必要があり、それは(完全に不要な)作業です。
64ビットでは仮想メモリはほぼ無料です。基本的なアプローチは「もしあれば、それを使用する」です。他のアプリケーションを制限しているわけではありません。そして、doが実際にそれを使用することになった場合、かなりの労力を節約できます。しかし、その時点が来るまで、あなたは予約しか持っていません。物理メモリにはまったく変換されません。あなたは今夜来てテーブルに座る友人にお金を払わないが、もし彼らが来たら彼らが座るスペースをまだ持っている-そして彼らが最終的に来て初めてあなたは実際に「チャージ」される。
Javaが異なるマシンおよび異なるバージョンで動作する方法についての詳細は、この質問を参照してください。 SunのJVMのデフォルトの最大ヒープサイズはJava SE 6? ヒープは連続したアドレススペースである必要があるため、最大ヒープサイズは予約された仮想メモリの量も決定します。事前予約されていないと、ヒープが他の誰かがヒープを拡張する必要がある場所にアドレス空間の領域を予約したため、この最大値まで拡張します。
プログラムがそのメモリを使い果たしているのではなく、Java VMロードされているプログラムに関係なく、そのメモリを予約しています。
仮想メモリアドレス指定を使用する最新のコンピューターアーキテクチャ(アプリケーションが認識する「メモリスペース」が実際に実際に物理的に割り当てられたメモリに関連していない場合)では、実際にはどのように関係ないことがわかりますこの仮想「メモリスペース」の多くは、起動時にアプリケーションに与えられます。これだけのメモリがシステムによって割り当てられたという意味ではありません。
アプリケーションが10GBの仮想アドレス空間を見つけた場合、アプリケーションに通知するのは、それがmay必要に応じて最大10GBのメモリアドレスを使用することだけです。ただし、実際に書き込まれるまで、メモリは物理的にRAMに割り当てられません。これはページごとに行われます。ページはメモリの4kBセクションです。仮想アドレス空間は、まさにそれです-実際に使用されるまで完全に仮想。
アプリケーションに10GBのアドレス空間が与えられ、その一部を使用し始めたとしましょう。この仮想メモリの「新鮮な」(以前は変更されていなかった)ページが最初に書き込まれると、システムはこの仮想ページを物理メモリのセクションに低レベルで「マッピング」してから書き込みます。しかし、そのアプリケーション自体はそのような詳細について心配する必要はなく、まるでメモリの仮想領域に完全にアクセスできるかのように動作します。
Javaアプリケーションの場合、アプリケーション自体ではなく、Javaがそのアドレス空間に割り当てられ、Javaデフォルトでは単に巨大なアドレス空間を要求します-要求する量は物理メモリサイズに関連して計算されますが、控えめにする必要があるからではなく、実用性のためだけです-アプリケーションはおそらく notですサーバーを完全にひざまずかせるのに十分なヒープサイズが必要になるため、サーバーはそうではないという前提で動作しています。上記で述べたように、これは「割り当てられた」ことを意味しません。そうするリソース。
あなたがドキュメントストレージビジネスにいると想像してください。紙の箱を保管する都市の中央に小さな施設があり、町の外に1000倍のスペースがあるはるかに大きな倉庫があります。すべてのボックスには、その内容を識別するラベルが付いています。
市内の施設はメインメモリです。ウェアハウスはディスク容量です。
新しいプロセスに10GBの仮想メモリを割り当てたからといって、新しい顧客に100億個のボックスを割り当てることができるわけではありません。これは、100億ラベルの印刷連続するID番号のあるボックスの場合を意味します。
これは、アプリケーションが実際に使用している物理メモリの量ではありません。すべてのプロセスで使用される仮想メモリは、明らかな問題なしに、マシン上の物理的RAM=.
プログラムはそれほど多くのメモリを使用していません。 JVM/OSはそのメモリを予約しています。つまり、プログラムが使用できる上限です。また、答えの1つが明確に言及しているように。 32ビットと64ビットはこれとは何の関係もありません。 32ビットは、最大2 ^ 32の物理メモリロケーションにアクセスできることを意味します。 64ビットは2 ^ 64までを意味します。