Jbossで実行されているj2eeアプリケーションがあり、そのメモリ使用量を監視する必要があります。現在、次のコードを使用しています
System.gc();
Runtime rt = Runtime.getRuntime();
long usedMB = (rt.totalMemory() - rt.freeMemory()) / 1024 / 1024;
logger.information(this, "memory usage" + usedMB);
このコードは正常に機能します。つまり、現実に対応した記憶曲線を示しています。 DBから大きなxmlファイルを作成すると、曲線が上がり、抽出が完了すると曲線が下がります。
コンサルタントは、明示的にgc()を呼び出すことは間違っていると言い、「jvmにいつgcを実行するかを決定させます」。基本的に彼の議論は ここで議論された と同じでした。しかし、私はまだ理解していません:
VMメモリで何が起こっているのかを本当に見たい場合は、 VisualVM のような優れたツールを使用する必要があります。このソフトウェアは無料であり、何が起こっているのかを見てください。
明示的なgc()呼び出しで実際に「間違った」ものはありません。ただし、gc()を呼び出すと、ガベージコレクターが実行されることを「示唆」していることに注意してください。そのコマンドを実行した正確な時間に実行されるという保証はありません。
VMのメモリ使用量を監視できるツールがあります。 VMはJMXを使用してメモリ統計を公開できます 。また、 GC統計の出力 を使用して、メモリの経時的なパフォーマンスを確認することもできます。
System.gc()を呼び出すと、オブジェクトが新世代から旧世代に早期に移動され、弱参照が早期にクリアされるため、GCのパフォーマンスが低下する可能性があります。これにより、メモリ効率が低下し、GC時間が長くなり、キャッシュヒットが減少します(弱い参照を使用するキャッシュの場合)。私はあなたのコンサルタントに同意します:System.gc()は悪いです。コマンドラインスイッチを使用して disable it に進みます。
stagemonitor をご覧ください。これは、オープンソースJava(web)アプリケーションパフォーマンスモニターです。応答時間メトリック、JVMメトリック、要求の詳細(要求プロファイラーによってキャプチャされた呼び出しスタックを含む)などをキャプチャします。オーバーヘッドはとても低い。
必要に応じて、素晴らしい時系列データベースグラファイトを使用して、派手なダッシュボードで見ることができるデータポイントの長い履歴を保存できます。
例:
プロジェクトのウェブサイト を見て、スクリーンショット、機能の説明、ドキュメントをご覧ください。
注:私はstagemonitorの開発者です
私は、コンサルタントは理論上正しいと言い、あなたは実際に正しいと言います。 言うことになる :
理論的には、理論と実践は同じです。実際にはそうではありません。
Java仕様は、System.gcがガベージコレクションを呼び出すことを提案していることを示しています。実際には、スレッドを生成し、Sun JVM上ですぐに実行します。
理論的には、ガベージコレクションのJVM実装を微調整することができますが、そこにあるJVMにデプロイすることを目的とした汎用コードを書いている場合を除き、心配する必要はありません。それがあなたのために働くなら、それをしてください。
Visual VMを使用して、Tomcatの内部で何が起こっているのかを確認します。 http://www.skill-guru.com/blog/2010/10/05/increasing-permgen-size-in-your-server/
実稼働システムでSystem.gc()を明示的に実行するのはひどい考えです。メモリが任意のサイズに達すると、フルGCの実行中にシステム全体がフリーズする可能性があります。マルチギガバイトサイズのサーバーでは、jvmの構成方法やヘッドルームの大きさなどに応じて、これは簡単に非常に顕著になります-30秒以上の一時停止が見られました。
別の問題は、GCを明示的に呼び出すことで、JVMがGCをどのように実行しているかを実際に監視せず、実際に変更していることです。JVMの構成方法に応じて、適切な場合、通常は増分的にガベージコレクションを実行します(メモリが不足すると、フルGCが実行されるだけではありません)。印刷するものは、JVMが単独で行うこととは異なります。1つは、メモリを手動でクリアするため、自動/増分GCの数が少なくなる可能性があります。
Nick Holtの投稿が指摘しているように、GCアクティビティを出力するオプションはすでにJVMフラグとして存在しています。
自由に印刷して適切な間隔で利用できるスレッドを作成できます。これにより、実際のメモリ使用量が表示されます。
JVM引数を見てください: http://Java.Sun.com/javase/technologies/hotspot/vmoptions.jsp#DebuggingOptions
XX:-PrintGCガベージコレクションでメッセージを出力します。管理可能。
-XX:-PrintGCDetailsガベージコレクションで詳細を出力します。管理可能。 (1.4.0で導入されました。)
-XX:-PrintGCTimeStampsガベージコレクションでタイムスタンプを出力します。管理可能(1.4.0で導入されました。)
-XX:-PrintTenuringDistribution保有期間情報を出力します。
System.gc()
を明示的に呼び出してJVMを混乱させることはありませんが、期待する効果が得られない場合があります。 Brian Goetz が書いたものすべてを読んで、JVMのメモリで何が起こっているのかを本当に理解するため。
コマンドラインからこれを行う素敵な方法が好きなら、jstatを使用してください:
http://Java.Sun.com/j2se/1.5.0/docs/tooldocs/share/jstat.html
設定可能な間隔で生情報を提供します。これは、ロギングやグラフ作成に非常に役立ちます。
JMXが提供するGC実行の履歴を使用する場合、同じ前後の数値を使用できますが、GCを強制する必要はありません。
これらのGCの実行(通常は古い世代と新しい世代)が通常のインターバルではないことに注意する必要があります。そのため、プロットの開始時間も抽出する必要があります(または、ほとんどの場合、プロットに十分な実用的な目的)。
たとえば、Oracle HotSpot VM ParNewGCの場合、Java.lang:type=GarbageCollector,name=PS Scavenge
というJMX MBeanがあり、LastGCInfo属性があり、最後のYGスカベンジャー実行のCompositeDataを返します。 duration
、絶対startTime
およびmemoryUsageBefore
およびmemoryUsageAfter
で。
タイマーを使用してその属性を読み取ります。新しいstartTimeが表示されるたびに、それが新しいGCイベントを記述することがわかっている場合は、メモリ情報を抽出し、次の更新のためにポーリングを続けます。 (AttributeChangeNotification
が何らかの形で使用できるかどうかはわかりません。)
ヒント:タイマーで、最後のGC実行までの距離を測定することがあります。それが長すぎてプロットを再開できない場合は、条件付きでSystem.gc()を呼び出すことができます。しかし、OLTPインスタンスではそれを行いません。
Java 1.5)を使用する場合、ManagementFactory.getMemoryMXBean()を見ると、あらゆる種類のメモリ、ヒープ、非ヒープ、perm-genの数値が得られます。
良い例がそこにあります http://www.freshblurbs.com/explaining-Java-lang-outofmemoryerror-permgen-space
提案されているように、VisualVMを試して基本的なビューを取得してください。
Eclipse MATを使用して、より詳細なメモリ分析を行うこともできます。
プログラムの正確性のために、System.gc()に依存しない限り問題ありません。
System.gcの問題は、JVMがメモリ使用量に基づいてガベージコレクターにすでに自動的に時間を割り当てることです。
ただし、たとえば、モバイルデバイスのように非常にメモリが限られた状態で作業している場合、System.gcを使用すると、このガベージコレクションにより多くの時間を手動で割り当てることができますが、CPU時間はかかります(ただし、 、gcのパフォーマンスの問題についてはそれほど心配していません。
ベストプラクティスは、おそらく大量の割り当て解除を行う可能性がある場合にのみ使用することです(大きな配列のフラッシュなど)。
あなたは単にメモリ使用量を心配しているので、すべてを検討してください.gcを呼び出すことをお気軽に、またはもっと良いことに、それがあなたの場合にメモリの違いの多くをもたらすかどうかを確認してから決定してください。