2

メモリリークがあると思います。
(最初のステップは問題を認めることだと彼らは言いますよね?)

とにかく、私はそうだと思います - 地域ごとのヒープの添付画像を参照してください: ヒープ領域. 緑はエデン、青/赤はS0/S1、紫はオールド。私は無制限の在職期間 (> 15) を持っており、メモリが割り当てられてから古い世代に流出するまでに多くの時間が経過しました。したがって、メモリリークです。おもう。

では、問題は、何が漏れているのかを分析するにはどうすればよいでしょうか? ご覧のとおり、私の Eden は非常にアクティブです。多くのオブジェクトが常に作成および破棄されています。

古い世代だけのヒープダンプを取る方法はありますか? または、完全なヒープダンプで古い世代を特定しますか (そうであれば、どのツールを使用しますか)?

編集 1: 明確化:オブジェクトをメモリに保持する必要があることは何もしていません。最初の起動後に割り当てたものはすべて、若くして死ぬはずです。

Edit2: 新しい調査結果: 私はヒープ ダンプを取得し、狂ったように GC を実行し、別のダンプを取得しました。2 つ目は、古い世代の使用率が大幅に低下したことを示しています。2 つの主な違いは、ファイナライザーが保持するオブジェクトでした。ファイナライザーは若い GC サイクルで実行されませんか? 彼らは常に完全な GC がクリーンアップされるのを待ちますか?

4

2 に答える 2

2

いくつかのものが古い世代に伝播するのを見るのは大きな問題ではありません。古い世代が特定のしきい値に達すると、完全なGCが開始されます。それでもメモリを再利用できない場合は、問題があります。若いコレクション中に割り当てられたメモリが表示されているという事実は、心配する必要はありません。

メモリが割り当てられてから古い世代に流出するまでに多くの時間が経過しました。したがって、メモリリーク。おもう

実はそうではありません。古い世代にメモリが追加されているからといって、それがメモリリークであるとは限りません。若いコレクションでは、古いオブジェクトが古い世代に昇格するのが通常の方法です。古いオブジェクトが古い世代に追加されるのは、それらの若いコレクションの間です。これは、アプリケーションがまだ立ち上がっているだけかもしれません。大規模なアプリケーションでは、毎日使用されない機能が存在する可能性があります。これは、予想よりも後でメモリに取り込まれる可能性があります。

そうは言っても、古い世代に追加されるメモリに本当に関心があり、さらに調査したい場合は、このアプリケーションをデモ環境で実行することをお勧めします。プロファイラーを接続し(VisualVMが機能します)、アプリケーションの負荷テスト(JMeterは優れていて無料です)を行います。オブジェクトを見ると、オブジェクトがどの世代であるかがわかります。また、古い世代が完全なGCが開始されるしきい値(通常は70%〜90%の範囲)に達したときに何が起こるかを確認する必要があります。古い世代が20%のしきい値に戻った場合、リークはありません。場合によっては、古い世代が完全なGCが開始されるポイントに到達しない可能性がありますが、代わりに期待どおりに横ばいになります。負荷テストはそれを特定するのに役立ちます。

回復せず、メモリリークがあることを確認した場合は、ヒープダンプ(hprof)をキャプチャし、MAT(メモリアナライザツール)などのツールを使用してダンプを分析し、原因を特定する必要があります。

于 2012-05-17T13:29:29.503 に答える
1

JVisualVM (Java 6 Build 10 以降の JDK の一部など) を使用すると、メモリ内にあるオブジェクトの TYPE を確認できます。これは、リークがどこにあるかを追跡するのに役立ちます。もちろん、コードを深く掘り下げる必要がありますが、これは常に利用可能で信頼できる、私が使用した中で最高のツールです。

渡されるオブジェクトに注意してください。クリアされていないリストまたは配列に保持されているハンドルがある可能性があります。JVisualVM で作成および保持されているオブジェクトの数を数分間監視すると、問題のあるオブジェクトが解放されていないことを確認するために、コードのどこを探せばよいかがわかります。

于 2012-05-17T11:50:09.833 に答える