2

HP-UX 環境の特定の Java アプリケーションで奇妙な問題が発生しています。

ヒープは -mx512 に設定されていますが、gpm を使用してこの Java プロセスのメモリ領域を確認すると、1.6GB 以上の RSS メモリを使用し、1.1GB が DATA 領域に割り当てられていることがわかります。24 ~ 48 時間で非常に急速に成長し、その後大幅に減速しますが、数時間ごとに 2MB ずつ増加します。ただし、Java ヒープにはリークの兆候は見られません。

これがどのように可能であったかについて少し調べてみたところ、Java ヒープと C ヒープのメモリ リークに関する HP の記事が見つかりました: http://docs.hp.com/en/JAVAPERFTUNE/Memory-Management.pdf

私の質問は、C ヒープと Java ヒープで何が実行されるかを決定するものです。Java ヒープを介して実行されないものについては、C ヒープで実行されているオブジェクトをどのように識別しますか? さらに、Java ヒープは C ヒープ内にありますか?

4

3 に答える 3

5

Java プロセスを構成するものを考えてみましょう。

あなたが持っている:

  • JVM (C プログラム)
  • JNI データ
  • Java バイトコード
  • Java データ

特に、それらはすべて C ヒープに存在します (当然、JVM ヒープは C ヒープの一部です)。

Java ヒープには、単純に Java バイト コードと Java データが含まれます。しかし、Java ヒープにもあるのは「空き領域」です。

典型的な (つまり、Sun の) JVM は、必要に応じて Java ヒープを拡大するだけで、縮小することはありません。定義された最大値 (-Xmx512M) に達すると、成長を停止し、残ったものを処理します。その最大ヒープが使い果たされると、OutOfMemory 例外が発生します。

Xmx512M オプションがしないことは、プロセス全体のサイズを制限することです。プロセスの Java ヒープ部分のみを制限します。

たとえば、10 MB の Java ヒープを使用するが、500 MB の C ヒープを割り当てる JNI 呼び出しを呼び出す不自然な Java プログラムを作成できます。Java ヒープが小さいにもかかわらず、プロセス サイズがいかに大きいかがわかります。また、新しい NIO ライブラリを使用すると、ヒープの外部にメモリをアタッチすることもできます。

考慮しなければならないもう 1 つの側面は、Java GC は通常、「コピー コレクター」であるということです。つまり、収集しているメモリから「ライブ」データを取得し、メモリの別のセクションにコピーします。コピー先のこの空きスペースは、少なくとも Xmx パラメータに関してはヒープの一部ではありません。これは「新しいヒープ」のようなもので、コピー後にヒープの一部になります (古いスペースは次の GC に使用されます)。512MB のヒープがあり、それが 510MB の場合、Java はライブ データをどこかにコピーします。素朴な考えは、別の大きなオープンスペース (500+MB など) に対するものです。すべてのデータが「ライブ」である場合、コピー先としてそのような大きなチャンクが必要になります。

したがって、最も極端なケースでは、特定のヒープ サイズを処理するには、システムに少なくとも 2 倍の空きメモリが必要であることがわかります。512MB のヒープには少なくとも 1GB。

実際にはそうではないことが判明し、メモリの割り当てなどはそれよりも複雑ですが、ヒープ コピーを処理するために大量の空きメモリが必要であり、これはプロセス全体のサイズに影響を与えます。

最後に、JVM は起動を容易にするために rt.jar クラスを VM にマッピングするなどの楽しいことを行うことに注意してください。それらは読み取り専用ブロックにマップされ、他の Java プロセス間で共有できます。これらの共有ページは、すべての Java プロセスに対して「カウント」されますが、実際には物理メモリは 1 回しか消費されません (仮想メモリの魔法)。

プロセスが成長し続ける理由については、Java OOM メッセージが表示されない場合、それはリークが Java ヒープにないことを意味しますが、他の何か (JRE ランタイム、サードパーティの JNI ライブラリ、ネイティブ JDBC ドライバーなど)。

于 2008-09-17T00:22:02.673 に答える
3

一般に、Java オブジェクトのデータのみが Java ヒープに格納され、Java VM が必要とする他のすべてのメモリは、「ネイティブ」または「C」ヒープから割り当てられます (実際、Java ヒープ自体は、割り当てられた 1 つの連続したチャンクにすぎません)。 C ヒープから)。

JVM では Java ヒープ (世代別ガベージ コレクションが使用されている場合はヒープ) がメモリの連続した部分である必要があるため、通常、JVM の起動時に最大ヒープ サイズ全体 (-mx 値) が割り当てられます。実際には、Java VM はこのスペースの使用を最小限に抑えようとするため、オペレーティング システムは実際のメモリを予約する必要がありません (OS は、ストレージの一部が書き込まれたことがないことを十分に認識できます)。 .

したがって、Java ヒープはメモリ内で一定量の領域を占有します。

残りのストレージは、Java VM と使用中の JNI コードによって使用されます。たとえば、JVM は、ロードされたクラスからの Java バイトコードと定数プール、JIT コンパイル済みコードの結果、JIT コードをコンパイルするための作業領域、ネイティブ スレッド スタック、およびその他のさまざまなものを格納するためのメモリを必要とします。

JNI コードは、「ネイティブ」メソッドの形式で Java オブジェクトにバインドできるプラットフォーム固有の (コンパイルされた) C コードです。このメソッドが実行されると、バインドされたコードが実行され、C ヒープのメモリを消費する標準 C ルーチン (malloc など) を使用してメモリを割り当てることができます。

于 2008-09-17T00:06:15.333 に答える
1

あなたが示した数字から推測できるのは、Java VM でのメモリ リークです。参照した論文に記載されている他の VM のいずれかを試してみてください。もう 1 つの (はるかに難しい) 代替手段は、HP プラットフォームでオープン Java をコンパイルすることです。

Sun の Java はまだ 100% オープンではありません。彼らはそれに取り組んでいますが、sourceforge にはそれがあると私は信じています。

ちなみに、Javaもメモリをスラッシングします。ときどき、OS のメモリ管理を少し混乱させます (Windows がメモリを使い果たし、Java にいくらか解放するように要求したり、Java がすべてのオブジェクトに触れたりしてスワップファイルからそれらをロードしたり、Windows が苦痛に悲鳴を上げたりして死んでしまった場合に見られます) が、私はそれがあなたが見ているものだとは思わない。

于 2008-09-16T23:55:23.080 に答える