私の単純な目標は、Java アプリケーションのメモリ使用量を監視して、アプリケーションがOutOfMemoryError
.
はい、言うのは簡単ですが、正しい解決策を考え出すことは非常に複雑に思えます。複雑な要因のいくつかは次のとおりです。
- さまざまなヒープ領域があり、それぞれが次をスローできます
OutOfMemoryError
。- 独自の
permgen
サイズ制限があるスペース ( で設定-XX:MaxPermSize=
) - 全体のヒープ領域 ( で設定
-Xmx
)
- 独自の
- VM は、ガベージ コレクションを実行する前に、ほぼすべてのヒープを割り当てる可能性があります。アプリケーションが多くのソフト参照を使用している場合、実際、これは確実に発生します。したがって、ヒープ割り当てのパーセンテージが高いからといって、アプリケーションが
OutOfMemoryError
. System.gc()
VM が再利用可能なすべてのオブジェクト (参照されていないオブジェクトや弱く参照されているオブジェクト) を再利用することが保証されていればよいのですが、そうではありません。そのため、呼び出しSystem.gc()
てからRuntime.freeMemory()
信頼できません。- ファイナライズのためにキューに入れられたオブジェクトはメモリを占有しますが、(通常は) ファイナライズ後に解放されます。したがって、ファイナライザー スレッドがそれらに到達したかどうかは、(見かけの) メモリ使用量に影響します (VM は、OOM をスローする前の最後の絶望的な行為としてファイナライザーを実行しますか?そのようには見えません。 )
- ネイティブ コードも同様にメモリを消費し、使いすぎると OOM が発生する可能性があります (これは私の特定のアプリケーションでは起こりそうにありませんが、全体像に別の複雑さを追加します)。
では、次の質問に答える適切で信頼できる方法は何でしょうか:私の Java アプリケーションは をスローするようになっていOutOfMemoryError
ますか?
別の言い方をすれば、アプリケーション バージョン X は問題なく動作し、メモリ リークもありませんが、バージョン X + 1 には認識されない遅いメモリ リークがあるとします。バージョン X + 1 が をスローする前に、この監視によってアラートを受け取りOutOfMemoryError
たいのですが、まったく同じ監視でバージョン X の誤検知が発生しないようにしたいと考えています。この監視の設定には調整が必要な場合があります。問題ありません.
考えられる答えの 1 つは次のようなものかもしれません: 過去 N 回の「完全な」GC 実行における、GC 実行直後のヒープ使用率の最大値は? この値が割り当てられたメモリの合計の X% を超える場合は、アラームを鳴らします。
アイデアは、「アプリケーションのメモリ使用量」をパーセンテージなどの単純な数値、または LOW、MEDIUM、HIGH などの数値で判断し、この値を監視することです。
jstatコマンドは多くの関連情報を提供しますが、問題はそれを単純な答えに要約し、上記の複雑な要因によって引き起こされる誤検知 (または誤検知) を回避することです。