9

私は最近、VisualVM を使用して作成している osgi Java アプリケーションのプロファイリングを開始しました。私が気づいたことの 1 つは、アプリケーションが (JMS 経由で) クライアントにデータを送信し始めると、ロードされるクラスの数が一定の割合で増加し始めることです。ただし、ヒープ サイズと PermGen サイズは一定のままです。データの送信を停止しても、クラスの数は決して減りません。これはメモリリークですか?ロードされたクラスをどこかに保存する必要があるためだと思いますが、アプリケーションを数時間実行しても、ヒープと permgen は増加しません。

プロファイリング アプリケーションのスクリーンショットについては、こちらを参照してください。

4

6 に答える 6

5

どういうわけか、その場で新しいクラスを動的に作成していますか?

ご協力いただきありがとうございます。私は問題が何であるかを理解しました。私のクラスの 1 つで、Jaxb を使用して XML 文字列を作成していました。これを行う際に、JAXB はリフレクションを使用して新しいクラスを作成します。

JAXBContext context = JAXBContext.newInstance(this.getClass());

そのため、JAXBContext はヒープ内を動き回っていませんでしたが、クラスはロードされていました。

プログラムを再度実行したところ、予想どおり通常のプラトーが表示されます。

于 2008-10-03T17:25:00.590 に答える
4

次のようなホットスポット フラグが、この動作を理解するのに役立つ場合があります。

  • -XX:+TraceClassLoading
  • -XX:+TraceClassUnloading

これは良いリファレンスです:

http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp

于 2008-10-03T17:03:50.757 に答える
4

あなたの問題がバイトコード生成に関連していることは間違いありません。

多くのライブラリは、CGLib、BCEL、Javasist、または Janino を使用して、実行時に新しいクラスのバイトコードを生成し、制御されたクラスローダーからそれらをロードします。これらのクラスを解放する唯一の方法は、クラスローダーへのすべての参照を解放することです。

クラスローダはクラスごとに保持されるため、これは、すべてのクラスへの参照も解放してはならないことを意味します [1]。適切なプロファイラーでこれらをキャッチできます (私は Yourkit を使用します - 同じ保持サイズを持つ複数のクラスローダー インスタンスを検索します)

問題の 1 つは、JVM がデフォルトでクラスをアンロードしないことです (理由は下位互換性です。静的初期化子は 1 回だけ実行されると (誤って) 想定しているためです。実際には、クラスがロードされるたびに実行されます)。アンロードを有効にするには、次のオプションを使用して渡す必要があります。

-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled

(JDK 1.5 でテスト済み)

それでも、過度のバイトコード生成は良い考えではないため、コードを調べて原因を見つけ、生成されたクラスをキャッシュすることをお勧めします。頻繁に問題を起こすのは、スクリプト言語、動的プロキシ (アプリケーション サーバーによって生成されたものを含む)、または巨大な Hibernate モデル (この場合、permgen を増やすだけです) です。

以下も参照してください。

  1. http://blogs.oracle.com/watt/resource/jvm-options-list.html
  2. http://blogs.oracle.com/jonthecollector/entry/presenting_the_permanent_generation
  3. http://forums.sun.com/thread.jspa?messageID=2833028
于 2008-10-03T17:44:55.840 に答える
3

誤解しない限り、ここではインスタンスではなく、ロードされたクラスを見ています。

コードが最初にクラスを参照するとき、JVM は ClassLoader を実行させ、クラスに関する情報を .class ファイルなどから取得します。

どのような条件下でクラスをアンロードするのかわかりません。確かに、静的情報を持つクラスをアンロードするべきではありません。

したがって、アプリケーションが実行されると領域に入り、新しいクラスを参照するので、ロードされるクラスの数がどんどん増えていくという、おおよそあなたのようなパターンが予想されます。

ただし、次の 2 つの点が奇妙に思えます。

  1. なぜ直線的なのか?
  2. なぜプラトーにならないのですか?

プログラムが参照するほとんどのクラスをJVMがすでにロードしているため、上昇傾向にありますが、不安定な線であり、増加すると先細りになると予想されます. つまり、ほとんどのアプリケーションで参照されるクラスの数には限りがあります。

どういうわけか、その場で新しいクラスを動的に作成していますか?

ベースライン ケースを取得するために、同じデバッガーでより単純なテスト アプリを実行することをお勧めします。次に、デバッグ情報を吐き出す独自の ClassLoader を実装することを検討するか、レポートを作成するツールがあるかもしれません。

ロードされているこれらのクラスが何であるかを理解する必要があります。

于 2008-10-03T16:52:53.573 に答える
0

Eclipse メモリ アナライザーを使用して、重複したクラスとメモリ リークをチェックします。同じクラスが複数回ロードされる場合があります。

よろしく、 マーカス

于 2008-10-10T15:24:58.023 に答える
0

はい、通常はメモリ リークです (実際にはメモリを直接扱うわけではないため、クラス インスタンス リークに近いものです)。私は以前にこのプロセスを経験したことがありますが、通常は古いツールキットに追加された一部のリスナーであり、それ自体を削除しませんでした。

古いコードでは、リスナー関係により、「リスナー」オブジェクトが残ります。古いツールキットや、あまり改訂されていないツールキットを調べます。後のJDKで実行されている既存のライブラリは、「リスナーの削除」の要件を削除する参照オブジェクトを認識します。

また、毎回ウィンドウを再作成する場合は、ウィンドウで dispose を呼び出します。そうしないと、それらがなくなることはないと思います(実際には、近い設定で破棄することもあります)。

Swing や JDK リスナーについて心配する必要はありません。それらはすべて参照を使用する必要があるため、問題はありません。

于 2008-10-03T16:36:33.073 に答える