21

キャッシュされたオブジェクトへのソフト参照を持つキャッシュがあります。キャッシュされたオブジェクトがクリアされたときに何が起こるかについて、キャッシュを使用するクラスの動作の機能テストを作成しようとしています。

問題は、ソフト参照を確実にクリアできないように見えることです。大量のメモリを使い果たすだけではうまくいきません。ソフト参照がクリアされる前に OutOfMemory が発生します。

Javaにソフト参照をより積極的にクリアさせる方法はありますか?


ここにあります

「ただし、OutOfMemoryError がスローされる前にすべての SoftReferences がクリアされることが保証されているため、理論的には OOME を引き起こすことはありません。」

つまり、上記のシナリオは、キャッシュされたオブジェクトのハード参照を保持しているクラスでどこかにメモリリークがあることを意味する必要がありますか?

4

10 に答える 10

15

問題は、ソフト参照を確実にクリアできないように見えることです。

これは、SoftReferences に固有のものではありません。Java のガベージ コレクションの性質上、ガベージ コレクション可能なものがいつでも実際に収集されるという保証はありません。簡単なコードでも:

Object temp = new Object();
temp = null;
System.gc();

最初の行でインスタンス化されたオブジェクトが、この時点で、または実際には任意の時点でガベージ コレクションされるという保証はありません。これは単に、メモリ管理された言語で対処しなければならないことの 1 つであり、これらのことに対する宣言力を放棄しています。そして、そうです、そのため、メモリ リークを確実にテストすることが困難になる場合があります。


とはいえ、引用したJavadocsによると、OutOfMemoryErrorがスローされる前にSoftReferencesを確実にクリアする必要があります(実際、それがそれらの全体的なポイントであり、デフォルトのオブジェクト参照と異なる唯一の方法です)。したがって、問題のオブジェクトへのより厳しい参照を保持しているという点で、ある種のメモリリークがあるように聞こえます。

JVM へのオプションを使用し-XX:+HeapDumpOnOutOfMemoryError、ヒープ ダンプをjhatなどにロードすると、オブジェクトへのすべての参照を確認できるため、ソフト オブジェクト以外の参照があるかどうかを確認できます。または、テストの実行中にプロファイラーを使用して同じことを達成することもできます。

于 2009-01-19T11:11:41.090 に答える
14

ソフト参照の処理方法を調整するための次のJVMパラメータもあります。

-XX:SoftRefLRUPolicyMSPerMB=<値>

ここで、「value」は、メモリの空きMbごとにソフト参照が残るミリ秒数です。デフォルトは1s/Mbであるため、オブジェクトがソフト到達可能である場合、1Mbのヒープスペースのみが空いている場合は1秒持続します。

于 2009-03-02T22:46:46.770 に答える
5

このコードを使用して、テストですべての SoftReferences を強制的にクリアすることができます

于 2010-09-28T07:20:26.197 に答える
2

通常のJVM実装(SUN)では、Softreferencesをクリーンアップするために、フルGCを複数回トリガーする必要があります。その理由は、たとえば、オブジェクトが再利用されたときに通知を受け取ることができるメカニズムなど、SoftreferencesではGCがより多くの作業を行う必要があるためです。

アプリケーションサーバーで多くのsofreferencesを使用するIMHOは、開発者がそれらがいつリリースされるかをあまり制御できないため、悪です。

于 2009-01-19T16:35:12.590 に答える
2

本当に必要な場合は、SoftReference で clear() を呼び出してクリアできます。

つまり、JVM が OutOfMemoryError をスローし、SoftReference がまだクリアされていない場合は、別の場所でオブジェクトへのハード参照が必要であることを意味します。そうしないと、SoftReference の契約が無効になります。そうしないと、SoftReference がクリアされることが保証されません。使用可能なメモリがまだある限り、JVM は SoftReference をクリアする必要はありません。一方、次回 GC サイクルを実行するときに、必要がなくても、それらをクリアすることができます。

また、VM はより攻撃的になる傾向があるため、WeakReferences を調べることを検討できます。技術的には、VM は WeakReference をクリアする必要はありませんが、オブジェクトが死んでいると見なされる場合は、次に GC サイクルを実行するときにそれらをクリーンアップすることになっています。キャッシュがクリアされたときに何が起こるかをテストしようとしている場合は、WeakReferences を使用すると、エントリがより速く消えるのに役立ちます。

また、これらはどちらも、GC サイクルを実行する JVM に依存していることに注意してください。残念ながら、これらのいずれかが発生することを保証する方法はありません。System.gc() を呼び出しても、ガベージ コレクターは単に peachy を実行していると判断し、何もしないことを選択する場合があります。

于 2009-01-19T14:21:58.350 に答える
1

ガベージ コレクションやソフト参照のようなその他の参照は非決定論的です。信頼できる処理を実行することは実際には不可能であるため、その時点でソフト参照が確実にクリアされるため、キャッシュがどのように反応するかをテストで判断できます。モックなどを使用して、より明確な方法で参照のクリアをシミュレートすることをお勧めします。テストは、GC が参照をクリーンアップするだけでなく、再現性があり、より価値があります。後者のアプローチを使用することは非常に悪いことであり、キャッシュと連携するコンポーネントの品質を向上させるのではなく、追加の問題を引き起こすだけです。

于 2009-01-19T11:09:42.793 に答える
0

キャッシュされたオブジェクトにはファイナライザーがありますか? ファイナライザーはオブジェクトへの新しい強力な参照を作成するため、SoftReference がクリアされても、後の GC サイクルまでメモリは再利用されません。

于 2009-09-16T13:21:45.913 に答える
0

ドキュメンテーションと私の経験から、私はそう言うでしょう:あなたはどこか別の場所に参照を持っている必要があります.

オブジェクトへのすべての参照 (Java 6 をデバッグするときの Eclipse 3.4 など) を表示し、OOM がいつスローされるかを確認できるデバッガーを使用することをお勧めします。

于 2009-01-19T11:11:39.403 に答える
0

Eclipse を使用する場合、ヒープ ダンプのデバッグを容易にするMemory Analyzerという名前のツールがあります。

于 2009-01-19T13:51:23.107 に答える