10

クライアントに代わってかなりのメモリとCPUを集中的に使用するタスクを実行するTomcat webappがあります。これは正常であり、望ましい機能です。ただし、Tomcat を実行すると、時間の経過とともにメモリ使用量が 4.0 GB まで急増し、開発マシンで実行されている他のすべてのものを混乱させるため、通常はプロセスを強制終了します。

ここに画像の説明を入力

自分のコードでうっかりメモリ リークが発生したと思っていましたが、VisualVM でチェックインしたところ、別の話が見えてきました。

ここに画像の説明を入力

VisualVM は、ヒープが約 1 GB の RAM を占有していることを示していますCATALINA_OPTS="-Xms256m -Xmx1024"

私のシステムは、VisualVM によるとほとんどメモリを消費していないのに、このプロセスが大量のメモリを消費しているように見えるのはなぜですか?


さらに調べてみると、アプリケーションで複数のジョブが同時に実行されている場合、メモリが解放されないことがわかりました。ただし、各ジョブが完了するのを待ってから別のジョブをBlockingQueueによってサービスに送信するExecutorServiceと、メモリは効果的にリサイクルされます。どうすればこれをデバッグできますか? ガベージ コレクションとメモリの再利用が異なるのはなぜですか?

4

2 に答える 2

11

制御したいものを制御することはできません-Xmx.Javaヒープのみを制御し、JVMによるネイティブメモリの消費を制御しません.JVM実装に基づいて完全に異なる方法で消費されます. VisualVM は、ヒープが消費しているものを表示するだけで、JVM 全体がOS プロセスとしてネイティブ メモリとして消費しているものを表示しません。それを確認するには、OS レベルのツールを使用する必要があります。JVM はまったく異なる方法でネイティブ メモリを使用するため、それらは根本的に異なる数値を報告します。通常、VisualVM が報告するものよりもはるかに大きくなります。

次の記事Thanks for the Memory (Understanding How the JVM uses Native Memory on Windows and Linux) から

ヒープとガベージ コレクターを維持すると、制御できないネイティブ メモリが使用されます。

Java ヒープを維持するメモリ管理システムの状態を維持するには、より多くのネイティブ メモリが必要です。空きストレージを追跡し、ガベージ コレクションの進行状況を記録するには、データ構造を割り当てる必要があります。これらのデータ構造の正確なサイズと性質は実装によって異なりますが、多くはヒープのサイズに比例します。

JIT コンパイラはネイティブ メモリを使用しますjavac

バイトコード コンパイルはネイティブ メモリを使用しますが (gcc などの静的コンパイラの実行にメモリが必要なのと同じように)、JIT からの入力 (バイトコード) と出力 (実行可能コード) の両方もネイティブ メモリに格納する必要があります。多くの JIT コンパイル メソッドを含む Java アプリケーションは、小さなアプリケーションよりも多くのネイティブ メモリを使用します。

そして、ネイティブメモリを使用するクラスローダーがあります

Java アプリケーションは、オブジェクト構造とメソッド ロジックを定義するクラスで構成されます。また、Java ランタイム クラス ライブラリ (java.lang.String など) のクラスを使用し、サード パーティのライブラリを使用する場合もあります。これらのクラスは、使用されている限りメモリに格納する必要があります。クラスの格納方法は、実装によって異なります。

スレッドのセクションを引用することさえし -Xmxません。あなたは、それが制御すると考えているものを制御せず、JVM ヒープを制御し、すべてが JVM ヒープに入るわけではなく、ヒープがさらに多くを占有するという考えを理解していると思います。管理と簿記のために指定したネイティブメモリ。

-Xmsプレーンでシンプルな JVM は、および-Xmxおよびその他のコマンド ライン パラメータで提供されるメモリよりも多くのメモリを使用します。

これは、JVMがメモリを割り当てて管理する方法に関する非常に詳細な記事です。質問の仮定に基づいて期待されるほど単純ではありません。包括的に読む価値があります。

多くの実装での ThreadStack サイズには、オペレーティング システムや場合によっては JVM のバージョンによって異なる最小制限があります。JVM または OS のネイティブ OS 制限よりも低い制限を設定すると、スレッドスタック設定は無視されます (代わりに *nix の ulimit を設定する必要がある場合があります)。他のコマンド ライン オプションも同じように機能し、指定された値が小さすぎると、黙ってより高い値にデフォルト設定されます。渡されたすべての値が実際に使用されているものを表していると想定しないでください。

クラスローダー、およびTomcatには複数あり、簡単に文書化されていない多くのメモリを消費します。JIT は大量のメモリを消費し、時間とスペースを交換します。これは、ほとんどの場合、適切なトレードオフです。

于 2012-08-02T00:40:21.493 に答える
0

CPU 使用率とガベージ コレクターも確認する必要があります。ガベージ コレクションが一時停止し、CPU gc がさらに消費してマシンの速度が低下する
可能性があります。

于 2012-08-02T00:46:41.777 に答える