過去1年間で、アプリケーションのJavaヒープ使用量を大幅に改善しました。これは66%の大幅な削減です。そのために、Javaヒープサイズ、CPU、Java非ヒープなどのさまざまなメトリックをSNMP経由で監視してきました。
最近、JVMによる実際のメモリ(RSS、常駐セット)の量を監視していて、少し驚いています。JVMによって消費される実際のメモリは、アプリケーションのヒープサイズ、非ヒープ、エデンスペース、スレッド数などとは完全に独立しているようです。
JavaSNMPで測定されたヒープサイズ Javaヒープ使用グラフhttp://lanai.dietpizza.ch/images/jvm-heap-used.png
KB単位の実メモリ。(例:1MBのKB= 1 GB) Javaヒープ使用グラフhttp://lanai.dietpizza.ch/images/jvm-rss.png
(ヒープグラフの3つのディップは、アプリケーションの更新/再起動に対応します。)
これは私にとって問題です。JVMが消費している余分なメモリはすべて、OSがファイルのキャッシュに使用できるメモリを「盗む」ためです。実際、RSS値が約2.5〜3 GBに達すると、アプリケーションからの応答時間が遅くなり、CPU使用率が高くなり始めます。ほとんどの場合、IO待機になります。スワップパーティションへのページングが始まると、これはすべて非常に望ましくありません。
だから、私の質問:
- なぜこうなった?「ボンネットの下で」何が起こっているのですか?
- JVMの実際のメモリ消費を抑えるにはどうすればよいですか?
残酷な詳細:
- RHEL4 64ビット(Linux-2.6.9-78.0.5.ELsmp#1 SMP Wed Sep 24 ... 2008 x86_64 ... GNU / Linux)
- Java 6(ビルド1.6.0_07-b06)
- Tomcat 6
- アプリケーション(オンデマンドHTTPビデオストリーミング)
- java.nioファイルチャネルを介した高I/O
- 数百から数千のスレッド
- データベースの使用量が少ない
- 春、休止状態
関連するJVMパラメーター:
-Xms128m
-Xmx640m
-XX:+UseConcMarkSweepGC
-XX:+AlwaysActAsServerClassMachine
-XX:+CMSIncrementalMode
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCApplicationStoppedTime
-XX:+CMSLoopWarn
-XX:+HeapDumpOnOutOfMemoryError
RSSの測定方法:
ps x -o command,rss | grep java | grep latest | cut -b 17-
これはテキストファイルに送られ、定期的に監視システムのRRDデータベースに読み込まれます。psはキロバイトを出力することに注意してください。
問題と解決策:
最終的に正しいことが証明されたのはATorrasの答えでしたが、を使用して正しい診断パスに私を導いたのはkdgregorypmap
でした。(両方の回答に投票してください!)これが起こっていたことです:
私が確かに知っていること:
- 私のアプリケーションは、3年以上前にアプリにコーディングしたJRobin1.4を使用してデータを記録および表示します。
- アプリケーションの最もビジーなインスタンスは現在作成します
- 起動から1時間以内に1000を超える新しいJRobinデータベースファイル(それぞれ約1.3MB)
- 起動後、毎日100以上
- 何か書き込むものがある場合、アプリはこれらのJRobinデータベースオブジェクトを15秒ごとに更新します。
- デフォルト構成のJRobin:
java.nio
ベースのファイルアクセスバックエンドを使用します。このバックエンドMappedByteBuffers
はファイル自体にマップされます。- 5分ごとに1回、JRobinデーモンスレッドが
MappedByteBuffer.force()
すべてのJRobin基盤データベースMBBを呼び出します
pmap
リスト:- 6500マッピング
- 5500は1.3MBのJRobinデータベースファイルで、これは最大7.1GBになります。
最後のポイントは私の「ユーレカ!」でした。一瞬。
私の是正措置:
- 明らかに優れている最新のJRobinLite1.5.2に更新することを検討してください
- JRobinデータベースに適切なリソース処理を実装します。現時点では、アプリケーションがデータベースを作成し、データベースがアクティブに使用されなくなった後は、データベースをダンプしません。
MappedByteBuffer.force()
定期的なタイマーではなく、データベース更新イベントに移動してみてください。問題は魔法のように消えますか?- すぐに、JRobinバックエンドをjava.io実装に変更します(行の行を変更します)。これは遅くなりますが、おそらく問題ではありません。これは、この変更の直接の影響を示すグラフです。
JavaRSSメモリ使用グラフhttp://lanai.dietpizza.ch/images/stackoverflow-rss-problem-fixed.png
私が理解する時間があるかもしれないし、ないかもしれない質問:
- JVM内で何が起こっているの
MappedByteBuffer.force()
ですか?何も変更されていない場合でも、ファイル全体が書き込まれますか?ファイルの一部?最初にロードしますか? - 常にRSSに一定量のMBBがありますか?(RSSは、割り当てられたMBBサイズの合計の約半分でした。偶然の一致ですか?そうではないと思います。)
MappedByteBuffer.force()
定期的なタイマーではなく、データベース更新イベントに移動した場合、問題は魔法のように解消されますか?- RSSスロープがそれほど規則的だったのはなぜですか?これは、アプリケーションの負荷メトリックのいずれとも相関していません。